knot-resolver 2.3.0 crashes in module/stats.
Overview
The crafted query from client and reply from auth server caused knot-resolver to crash in my fuzzing environment.
This issue may be caused by knot_dname_to_str
in libknot like #353, however verbose mode is not required in this issue.
# rm -f *mdb ; ./daemon/kresd -c /usr/local/etc/knot-resolver/kresd.conf
[system] interactive mode
> Segmentation fault
or
# rm -f *mdb ; ./daemon/kresd -c /usr/local/etc/knot-resolver/kresd.conf
[system] interactive mode
> stats.frequent()
Segmentation fault
Environment
IP Addresses of each servers.
- root DNS server: 192.168.33.100/24
- malicious authoritative server: 192.168.33.101/24
- victim full service resolver: 192.168.33.102/24
OS, Software of each servers.
root DNS server
- OS: CentOS 7.4 x86_64 on VirtualBox VM
- DNS: bind
Malicious authoritative server
- OS: CentOS 7.4 x86_64 on VirtualBox VM
victim full service resolver
- OS: CentOS 7.4 x86_64 on VirtualBox VM
- DNS: knot-resolver 2.2.0
Setup steps of Environment
root servers
Install CentOS 7.4 from install ISO image.
Set IP address VM to 192.168.33.100/24.
Set firewalld.
# firewall-cmd --zone=public --add-service=dns --permanent
# firewall-cmd --reload
Install Bind.
# yum install bind bind-utils
Upload and extract test-files.tar.gz
# cd /tmp
# tar xzf /path/to/test-files.tar.gz
Copy named.conf and root zone file.
# cp /tmp/test-files/root.named.conf /etc/named.conf
# cp /tmp/test-files/root.zone /var/named/root.zone
# chmod 644 /var/named/root.zone
Start named.
# systemctl start named
# systemctl enable named
Fuzzing authoritative server
Install CentOS 7.4 from install ISO image.
Set IP address to 192.168.33.101/24.
Set firewalld
# firewall-cmd --zone=public --add-service=dns --permanent
# firewall-cmd --reload
Install Build tools.
# yum install epel-release
# yum install gcc-c++ boost-devel wget perl yaml-cpp-devel bind bind-utils gtest-devel
# wget https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.sh
# sh cmake-3.10.0-Linux-x86_64.sh --skip-license --prefix=/usr/local
Install openssl 1.1.0 from source file.
# wget https://www.openssl.org/source/openssl-1.1.0g.tar.gz
# tar xzf openssl-1.1.0g.tar.gz
# cd openssl-1.1.0g
# ./config shared
# make
# make install
# echo /usr/local/lib64 > /etc/ld.so.conf.d/local.conf
# ldconfig
Upload and extract dns-fuzz-server.tar.gz, build fuzzing tool.
# cd /tmp
# tar xzf /path/to/dns-fuzz-server.tar.gz
# cd dns-fuzz-server
# cmake .
# make
Generate zone file and DNSSEC keys.
# named-checkzone -s full -o data/example.com.zone.full example.com data/example.com.zone
# (cd data && ./keygen.sh example.com RSASHA256 )
Start Fuzzing DNS service foreground.
# ./bin/knot_server -z example.com -f data/example.com.zone.full -K data/example.com.ksk.yaml -Z data/example.com.zsk.yaml
victim full service resolver
Install CentOS 7.4 from install ISO image.
Set IP address to 192.168.33.102/24.
Set firewalld.
# firewall-cmd --zone=public --add-service=dns --permanent
# firewall-cmd --reload
Install Build tools.
# yum install epel-release
# yum install gcc-c++ openssl-devel wget knot-devel bind-utils luajit-devel libuv-devel gdb
Install knot-resolver
# cd /tmp
# wget https://secure.nic.cz/files/knot-resolver/knot-resolver-2.3.0.tar.xz
# tar xJf knot-resolver-2.3.0.tar.xz
# cd knot-resolver-2.3.0
# make install LDFLAGS="-Wl,-rpath=/usr/local/lib -fvar-tracking" PREFIX="/usr/local" CFLAGS="-DNDEBUG -g"
Upload and extract test-files.tar.gz.
# cd /tmp
# tar xzf /path/to/test-files.tar.gz
Copy kresd.conf and hints file.
# cp /tmp/test-files/kresd.conf /usr/local/etc/knot-resolver
# cp /tmp/test-files/root.hints /usr/local/etc/knot-resolver
Start knot-resolver with gdb.
# cd /tmp/knot-resolver-2.3.0
# rm -f *mdb ; gdb ./daemon/kresd
(gdb) run -c /usr/local/etc/knot-resolver/kresd.conf
Login to auth server(192.168.33.101) and send queries to resolver.
# cd /tmp/dns-fuzz-server
# ./bin/knot_client -s 192.168.33.102 -i 200
Please wait several minutes or execute stats.frequent() in interactive mode.
Program received signal SIGSEGV, Segmentation fault.
lru_apply_impl (lru=lru@entry=0x7ffff7f04010,
f=f@entry=0x7ffff3a638d0 <dump_value>, baton=baton@entry=0x5555557bbaa0)
at lib/generic/lru.c:69
69 struct lru_item *it = g->items[j];
Missing separate debuginfos, use: debuginfo-install glibc-2.17-196.el7_4.2.x86_64 gmp-6.0.0-15.el7.x86_64 gnutls-3.3.26-9.el7.x86_64 knot-libs-2.6.6-1.el7.x86_64 libcap-ng-0.7.5-4.el7.x86_64 libffi-3.0.13-18.el7.x86_64 libgcc-4.8.5-16.el7_4.2.x86_64 libstdc++-4.8.5-16.el7_4.2.x86_64 libtasn1-4.10-1.el7.x86_64 libuv-1.19.2-1.el7.x86_64 lmdb-libs-0.9.18-1.el7.x86_64 luajit-2.0.4-3.el7.x86_64 nettle-2.7.1-8.el7.x86_64 p11-kit-0.23.5-3.el7.x86_64 zlib-1.2.7-17.el7.x86_64
(gdb) bt
#0 lru_apply_impl (lru=lru@entry=0x7ffff7f04010,
f=f@entry=0x7ffff3a638d0 <dump_value>, baton=baton@entry=0x5555557bbaa0)
at lib/generic/lru.c:69
#1 0x00007ffff3a63f0d in dump_list (env=0x7fffffffe140,
module=0x7ffff7f04010, args=<optimized out>, table=0x7ffff7f04010)
at modules/stats/stats.c:353
#2 dump_frequent (env=env@entry=0x7fffffffe140,
module=module@entry=0x555555799870, args=<optimized out>)
at modules/stats/stats.c:362
#3 0x000055555555fe6a in l_trampoline (L=0x40000378) at daemon/engine.c:579
#4 0x00007ffff67fcbd6 in lj_BC_FUNCC () from /lib64/libluajit-5.1.so.2
#5 0x00007ffff68402d0 in lua_pcall () from /lib64/libluajit-5.1.so.2
#6 0x000055555555e8cc in engine_pcall (L=<optimized out>,
argc=<optimized out>) at daemon/engine.c:789
#7 0x000055555556708e in execute_callback (L=L@entry=0x40000378,
argc=argc@entry=1) at daemon/bindings.c:1272
#8 0x0000555555568013 in event_callback (timer=0x5555557a5060)
at daemon/bindings.c:1290
#9 0x00007ffff72bd29e in uv__run_timers () from /lib64/libuv.so.1
#10 0x00007ffff72b0e92 in uv_run () from /lib64/libuv.so.1
#11 0x000055555555c519 in run_worker (args=0x7fffffffdf90,
leader=<optimized out>, ipc_set=0x7fffffffde10, engine=0x7fffffffe140,
loop=0x7ffff74cbd00) at daemon/main.c:422
---Type <return> to continue, or q <return> to quit---
#12 main (argc=<optimized out>, argv=<optimized out>) at daemon/main.c:755