Arvutiteaduse instituut
  1. Kursused
  2. 2020/21 kevad
  3. Turvalise programmeerimise meetodid (MTAT.07.015)
EN
Logi sisse

Turvalise programmeerimise meetodid 2020/21 kevad

  • HomePage
  • Lectures
  • Links
  • Homeworks

Debugger, memory layout, assembler

  1. Log in to the test system via ssh (hostname and logins provided on the blackboard).
  2. This test system has the following prerequisites already installed, this is just for reference when trying it on your own systems (install as root):
     apt-get install gcc build-essential nasm gdb prelink perl
    
  3. Optional: set your locale if you wish some other language messages:
     export LANG=en_US.UTF-8
    
  4. Download stack-demo.c: copy link location and use wget like this -
     wget -O stack-demo.c https://courses.cs.ut.ee/2019/secprog/spring/uploads/Main/stack-demo.c
    
  5. Read, discuss and understand it: what functions are called by what functions, what instances of variables are there during recursion, what does each function return?
  6. Compile it:
     gcc -o stack-demo stack-demo.c -g
    
  7. Run it under debugger:
     gdb ./stack-demo
    
  8. Put breakpoints to all the functions:
     b main
     b rec
     b stop_it
    
  9. Start the program:
     run
    
  10. Useful gdb commands:
cont(inue) continue execution
r restart execution of the program
s step (execution one line at a time)
l list the source (can take line number as argument)
si step into (execute one machine instruction at a time)
set disassembly-flavor intel selects disassembly syntax (you want to use this before first disassembly)
disass symbolname disassemble machine code
disass 0xXXX 0xXXX disassemble machine code in given address range
info reg contents of all the registers
x/150x $esp dump stack contents (amount of memory, $esp = register)
b N breakpoint on line N (source line)
b *0xXXXX breakpoint on memory address 0xXXXX
set args XXXX set command line arguments to the program
  1. Your task: examine the contents of stack on a running program and find
    • return address (also find the address of return address: 0xbf...... or 0xffff.... when running on 64-bit kernel like in test system)
    • arguments to the function (find them by values)
    • local variables of the function (find them by values)
  2. Disassemble all the functions and try to understand them. Find
    • calls to libc functions printf and sprintf,
    • initialization of local variables,
    • how is the value returned from functions?
  3. To read x86 assembly language (Intel syntax):
push regname push value of the register to stack (esp decreases automatically on push)
push 0x1234 push a imediate constant to stack
push [reg+8] push a value from memory, address = register + offset
mov regname, value assignment to a register
mov DWROD PTR [reg2], reg1 store reg1 to memory address shown in another register
lea same, for memory addresses
sub,add,xor arithmetics, to arguments, assigned to the second one!
cmp* ... comparision (sets flags)
jle, jge conditional goto
jmp addr unconditional goto
call addr function call (address of the next instruction pushed to stack!)
pop regname pop a value from stack (esp increases)
leave mov ebp,esp; pop ebp
ret return to address in stack
  1. Some more broken programs: overflow1.c overflow2.c. Compile them and create core dump with huge input values:
  2. Allow creation of core files - max size in kB or unlimited; ulimit influences only this shell and subprocesses
    ulimit -c unlimited
    
  3. Helpful constructions for large input (use larger sizes and real program names)!
     ./overflow1 $(perl -e 'print "A"x20')
     perl -e 'print "A"x20' | ./overflow2
    
  4. Examine core files (make sure the last core was generated from overflow1):
     gdb overflow1 core
    
    • What data was overwritten? What is the contents of registers?
  5. The next goal of the lab is to try to construct a working shellcode that just spawns a shell from a vulnerable program.
  6. (already done in lab environment) turn off address space randomization as root:
     sudo sysctl -w kernel.randomize_va_space=0
    
    This is needed if the attack code does not cope with randomization - like our code does at first.
  7. Download and compile s-proc wrapper - source: s-proc.c
     gcc -o s-proc s-proc.c
    
  8. Turn off nonexecutable stack protection on the resulting s-proc binary:
     /usr/sbin/execstack -s s-proc
    
    This is needed to turn off hardware NX bit on non-code areas to be able to execute the loaded code.
  9. Download exit.asm, read and understand it (syscall exit, eax=syscall number, ebx=syscall argument) and assemble it to machine code:
     nasm -o exit exit.asm
    
  10. Run the machine code fragment with the help of s-proc and look at the exit code:
     ./s-proc -e exit
     echo $?         
    
  11. Download exit2.asm, read and understand why it does the same. Try if it really does.
  12. Compare the machine code dump of exit and exit2. Which would work for shellcode injection? Why?
     ndisasm -b32 exit
     ndisasm -b32 exit2
    
  13. Download overflow3.c and compile it:
     gcc -o overflow3 overflow3.c -g
    
  14. Turn off nonexecutable stack protection on the resulting binary:
     /usr/sbin/execstack -s overflow3
    
    This is needed to turn off hardware NX bit on non-code areas to simplify our exploit code.
  15. Download exploit template stack.asm, read and understand it.
  16. The goal of the following items is to change NNNN so that crash EIP equals 0x60606060 - decrease if 0xff are there, increase otherwise. Start with slightly overflowing the buffer (look at overflow3 source to check buffer size). Repeat, including reassembling the code with nasm.
  17. Hint: running the program:
     ./overflow3 $(cat stack)
    
    Examining the core:
     gdb ./overflow3 core
    
    When done, examine the stack in gdb:
     x/1000x $esp-9000
    
    Here the first column is the address of first data column in the same row. Find the address of our code and put it instead of 0x60606060 in the code.
  18. To find the start of our code, disassemble the address range you suspect it to be in:
     disass 0xffffXXXX,0xffffYYYY
    
  19. To see the bytes of your exploit program, see
     ndisasm -b32 stack | less
    
    You should get a sh prompt if you succeed - repeat until you do.

Based on http://www.safemode.org/files/zillion/shellcode/doc/Writing_shellcode.html

  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused