# NULLCON: Exploitation 2
**Category:** Binary Exploitation**Points:** 300**Total Solves:** Not Available## Problem Description:[//]: # (Description of your problem. For eg use below description as a template)[//]: # (> This program is vulnerable to a format string attack! See if you can modify a variable by supplying a format string! The binary can be found at /home/format/ on the shell server. The source can be found [here](format.c\).)![Image](ProblemStatement.png?raw=true "Problem Statement")
## Write-up[//]: # (> Your write up goes here.)I am a beginner and this is one of the hardest exploit I have done. To solve this I teamed with my buddy Grant, who was kind enough to let me solve this one by own, and guided me through the process. We got started, and after downloading the binary named [pwn2-box.bin](pwn2-box.bin), first we had a look at the information about the file like - architecture, os, compilation flags, etc with the  command `checksec pwn2-box.bin`, which gave this:```    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX disabled    PIE:      No PIE (0x400000)    RWX:      Has RWX segments```
Looking at this told us few things, lets look at the each one by one.`Arch: amd64-64-little` tells that arhitecture is amd64-64, which means we will be dealing with 64bit registers. little tells us that executable is buid for little endian machine. 
`RELRO` aka Relocation Read Only is `Partial RELRO` which means, the ELF( Executabel and Linkable File) isgoing to have .got.plt and .plt sections. Where as .plt is going to be read-only but .got.plt isgoing to be writable. Just for additional info, .plt section is Procedure Linkage Table, and.got is Global Offset Table, but .got.plt is GOT of .plt section. When RELRO is Full Relro, lazylinking, means linking at compile time is disabled, which means linker resolves the symbol at loadtime (when program starts). That implies that .got.plt will be populated at load time, oncepopulated it will be moved in .plt section and .plt section is marked read only. So, there is no .got.plt section in FULL RELRO. If you want read more about .plt and .got.plt section [read here](https://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html) and RELRO [read here](https://mudongliang.github.io/2016/07/11/relro-a-not-so-well-known-memory-corruption-mitigation-technique.html)
There is no stack canary, can do buffer overflow easily.
NX is disabled, which means code can be executed on the stack and heap. NX enabled means there will be no segment with W^X, both write and execute permissions, and permissions of section will be enforced by OS, which mean if a section is marked as read OS will not allow write and execution in that section.
There is No PIE means all constant addreses are not going to be accessed with global offset table (GOT), instead with fix addresses.
By then, we had pretty good idea of attack vector we could use in the program.
As it's partial RELRO, we could modfify the symbols' resolved address to change the control flow, so it's worth to look at the symbos present in the binary, we checked the symbols present in the binary as:```$nm pwn2-box.binnm: pwn2-box.bin: no symbols```Huh.. no symbols, symbol table is stripped. We looked at the dynamic symbol resolutions:```$ objdump -T pwn2-box.bin 
pwn2-box.bin:     file format elf64-x86-64
DYNAMIC SYMBOL TABLE:0000000000000000      DF *UND*  0000000000000000              seccomp_init0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable0000000000000000      DF *UND*  0000000000000000              seccomp_rule_add0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 getpid0000000000000000      DF *UND*  0000000000000000              seccomp_load0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 mmap0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __assert_fail0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 memset0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 alarm0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 pipe0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 read0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 signal0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 perror0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 exit0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fork00000000006020a0 g    D  .data  0000000000000000  Base        _edata00000000006020a8 g    D  .bss   0000000000000000  Base        _end00000000006020a0 g    D  .bss   0000000000000000  Base        __bss_start0000000000400820 g    DF .init  0000000000000000  Base        _init0000000000400ec4 g    DF .fini  0000000000000000  Base        _fini
```Few symbols worth noticing were - seccomp based functions, mmap - memory is mapped into the programat run time, memset - setting the memory, alarm - generates SIGALARM, pipe and fork together - someinter process communication might be going on between child and parent process, read system call toread data, signal - register a signal handler, perror - print the error, exit - to exit theprogram.
Now at this point we were ready to look at the disassembled code of binary. Looking at it told usthat - program was creating a pipe, then forking a child process. Behavior of both the processes,child and parent, is descirbed ahead: parent process registers a signal handler for few signals,signal worth mentioning is `ALARM`. What handler does is it get's PID and exit the program with code 1. Alarmwas set up for 5sec, which means program is not going to run longer than 5 secs. After setting alarm,it reads 4 byte of data from STDIN, use this read value as an integer and compare that it's less than0x100000, if not it prints the error message "error" and parent process exits. Else, parent processallocates the memory of size read earlier at random location using mmap. Further itreads input from STDIN and writes to memory allocated with mmap. After allocating memory it initializes a seccomp on this allocated memory which can only make write, exit, exit\_group syscalls. Next is the interesting part, after setting up those seccomp rules,it reads upto the size of allocated memory from STDIN, and write to to allocated memory, and that's not it furtherexecutes it. Which means if we provide a shellcode that would going to be executed, but it can only dowrite, exit, group\_exit calls, otherwise we could have passed a shellcode to get the flag stored in/flag.txt file. Another important thing was to patch the alarm instructions, otherwiseit will be hard to debug as `alarm` call will call the handler and handler will exit the program.
Now the child process, it reads 1 byte from read side of PIPE, compares it with 0xA, if matched, read 4 more bytes, treat this 4 byte as an integer, and whatever the value of integer is, read that much bytesagain from read end of PIPE and store it in buffer on stack.
Looking at this exploit seemed clear - write shellcode which will be written to mmapped memory, andgets executed. As we could only do write system call, it's quite clear that we needed to pass theexploit to the child process. That could be done by our shellcode by writing it to the pipe through write end, the child process will store it on stack. My first apporach was to do buffer overflow, overwrit the return address to the part of my shellcode stored at parent process mmapped memory, which upon execution will give me shell.
So my whole shellcode breakdown was going to be like this:```comlete shellcode = [[stager][piped content][shell code to get bash]]piped content = [0xA][sizeof stack content][stack content]stack content = [[0x78*'a'] + [address of shellcode to get bash]]```
Stager is a shellcode which is going to figure out the address of piped content and write it to thepipe from parent process to child process. Initially address of shllcode content is not known so,stager will also update that address, as it can figure out the address where [stack content] willstart.
Piped content going to be processed by child process by reading it from read end of pipe. It has the '0xA' to satisfy the condition, the size of stack content going to be read by child process first as SIZE, then SIZE number of bytes will be read from pipe read end and store on the stack, which will cause the buffer overflow and return the control flow to my shellcode to give me shell.
Stack content is larger than buffer allocated for the data stored on stack and this will overwritethe RBP, and store the address of [shell code to get bash] below RBP, which is return address.
Below is my stager code:```    jmp short label1pop_addr:    pop rsi    mov rax, rsi    add rax, 0x85; added the size of piped content    mov [rsi + 0x85 - 8], rax; placing the address for return address    xor rax, rax    mov al, 1; write system call    xor rdi, rdi    mov rdi, 4;push 4 pipe descriptor    xor rdx, rdx    mov dl, 0x85; size to copy    syscalllabel1:    call pop_addr    ;here is content going to be piped    ;below will be another shellcode to give sh```
Plan seemed perfect, I put hours of effort in debugging and writing the script, then executing it to get the flag, aaaaand... I got memory access violation. Because, the shellcode I was executing to get sh was on mmapped memory which belonged to parent process, and I tried to execute it from child process. I didn't do a good job of looking ahead. Well lesson was learned. But now I had bigger issue, how to execute my shellcode to get the shell. Then my buddy grant directed me toward the ROP and using RSP gadget. I was not aware of this awesome technique, so I am going to write a bit about this also. Gadgets are insturctions that are already available in program, and can be executed, if one can get to know the address of those instruction, which we are calling gadget, at run time. As, in this case we have no ASLR, no PIE, if I could find a instruction which could do `call RSP` I can run my shell code on stack, this address is not gonna change as I said there is no PIE. Searching for this gadget in the binary, I got one which could help me to execute the shellcode:
```$ ROPgadget --binary CTFs/NULLCON/Binary-Exploit/Exploitation-2/pwn2-box.bin | grep "call rsp"0x0000000000400f7b : call rsp```
New plan was not much different from old one but just some changes here and there. I planned my new full shellcode to look like this: 
```comlete shellcode = [[stager][piped content]]piped content = [0xA][sizeof stack content][stack content]stack content = [[0x78\*'a'] + [address of ROP gadget] + [shell code to give bash]]```
What change does is, my shellcode to get sh is getting written on stack causing buffer overflow,and return address is pointing to gadget. So, when return statement gets executed, RSP getincremented by +8 and it will point to the my shellcode to get sh, as the ROP gadget executes,contorl goes to the shell code which gives the shell. The whole thing was put in the [script](solve.py). Executing this script gave the bash.
Thanks to @Digital\_Cold for guidance.## Other write-ups and resources
* None