I created a virtualbox VM with the ISO installed, and booted the VM. However I got a UEFI shell which is not the expected output, and I need to disable the EFI in the system configuration to boot normally
Once that is done, I get the following, which is nice
I have no information about any users to login to this, so I decided to inspect the iso.
I mounted the ISO on my host machine to check out the file contents using
the file contents looks like a normal bootable ISO, here are the contents
I looked into the casper
directory and I saw filesystem information, one of them is a squashfs filesystem.
I wanted to inspect this fs and look at the contents, so I used unsquashfs
to extract the files for me
The result of the ls
command returns this
seems like a normal linux system directory, I went to cat /etc/passwd to see which users are created
Thats a lot of users, and looks like the image also runs certain services we might be able to exploit mysql, ftp, www-data ...
but we'll explore that later.
I listed the users in the home directories and i got these
There are some users created and a LOOKATME folder which has a password
file, the contents of the file are like so lmezard:G!@M6f4Eatau{sF"
I entered the password in and i am able to login to the VM as lmezard
Here is the enumeration of the files in the home directory
It says that we need to get a new password, but didnt we already have one? I confirmed the SSH service is running using netstat -tulpn | grep LISTEN
and tried to SSH as lmezard
with the same password but It did not work.
Looks like we nede to solve the puzzle to get the actual password for SSH.
the fun
file is a posix tar archive, so I extracted at and there are alot of files..
They are not actually pcap files, just the extension is similar. All of these files are normal text files which contains a portion of C code.
After hours of pain, I have made a script that sorts all the files based on their content, and merge them together into 1 big file
grep -l '//file[0-9]*$'
* finds all files in current directory that contain the pattern '//file[0-9]*$'
.$file
being the current indexed elementtail -n 1 "$file"
extract the last line of the file where they have //fileNumber
, and the sed 's/.*file\([0-9]*\).*/\1/')
command extracts the numbersort -n | cut -d' ' -f2-
sorts the filenames by the number X and removes the numbers from the output.xargs cat > /dev/shm/out.c
concats the contents and merges them into one single fileMy script was not completely correct, so I still had to manually use vim to edit the final file. I learnt that in Vim :
V
to do a visual lightlightCtrl + F
to scroll one page down and Ctrl + B
to scroll ont page up/
to find stringsAfter everything is done and compiled, I get the output
The plaintext is Iheartpwnage
, and the ciphertext after SHA 256 is 330b845f32185747e4f8ca15d40ca59796035c89ea809fb5d30f4da83ecf45a4
Accodring to the instructions, I should be able to login as 'laurie', so lets give it a try…
And it works
And we have another puzzle… This time, its to another user called thor
and we are given an executable named bomb
The binary strings are abit sus, this might be a fork bomb or some sort.. but we ball
nevermind im just paranoid, no fork bomb here (yet)?
I tried messing around with it, looks like it opens arguments and reads from stdin as well
below are the lib calls from ltrace, nothing intuitive, just assigning a signal handler, read input and printf.
If no further information can be obtained, I guess we will need to reverse engineer it. since GDB is installed in our machine, we are able to launch GDB with a test input file using
I also have the gdbinit
file like the following
There is a function named phase1 in the assemble, so I would want to set a breakpoint there
Upon running the program, looks like they have a symbol that checks if a string is equal or not.
And eventually, we will reach a strlen call, we should be able to see what strings is it measuring. The first string its measuring is our input file,
And upon the second calling of strlen, we are able to see the string that they are measuring - Public speaking is very easy.
, this might be the clue for the first part of the bomb.
The second part was though, I eventually figured out that i need to pass in 6 numbers like this 1 11 111 111 11 11
, and they used that to measure the first criteria of the bomb like so
After the read the numbers, they validate the numbers in a weird way like so:
which gives a general formula
following the rule, the numbers 1 2 6 24 120 720
and it works so far
For the third phase, the password is 5t458
.
For phase 4, it has a function called func4
which takes the line as input and is recursive.
The recirsive function maps the input to output like so
This looks like a fibonacci-ish sequence, and its comparing the output to 0x37, which is 55 in decimal. The number should map to number 9.
Turns out it was correct, we are moving on to the next stage.
The keys so far are like so
for stage 5, it first expects a string of length 6, and it compares it to a string which seems like giants
based on the stringlength argument.
However, i did notice my input string oolala
gets transformed into ggusus
when strlen is called on it. which means this also implies an encryption.
I did some case analysis and obtained this mapping based on the behaviour of the code
To form the encrypted string giants
, we the input should be opekmq
. Turns out it was correct. Our keyfile should now look like so
Phase 6 calls the read_six_numbers
function, similar to phase 2.
After doing some studying, i find out these rules for key checking
After the initial validation, it looks like there is another section, which involves comparing the numbers 432, 212, 997, 301, 725, 253
which may be infered by the following data.
the single-digit numbers beside each individual 3 digit numbers may represent our input, so I decide to shuffle the input to validate any changes
The following is the access sequence for input 4 6 5 3 2 1
And the following is the access sequence for 4 1 2 3 5 6
turns out the number beside the digits is just node number, the input affects access seqeunce to compare.
Looking at the hint, number 4 (node 4) is placed at the first index. Which means that number 4 being accessed first is correct. I also noticed that they are comparing the elements beside each other. E.G if my input is 1 3 2 4 5 6
, i will compare the value of (node 1 > node 3) -> (node 3 -> node 2)…
This means that the value of the nodes needs to be sorted for the checking to pass.
And since we have 6 numbers corresponding to 6 nodes, 432(n6), 212(n5), 997(n4), 301(n3), 725(n2), 253(n1)
, we need to arrange them like so to make it sorted: 997(n4) 725(n2) 432(n6) 301(n3) 253(n1) 212(n5)
.
Since the key is which nodes will get access first from left to right, our key for this phase will be 4 2 6 3 1 5
Our final key will now look like
Trim them and remove newlines and spaces, you will get the password to the thor user
Publicspeakingisveryeasy.126241207205t4589opekmq426315
We also need to switch the last 2nd character and last 3rd character according to the subject
which results in
Publicspeakingisveryeasy.126241207205t4589opekmq426135
Doesnt work… Upon double checking the README, I realized that phase 3 might have more than 1 answer, I went back to check and made sure this time I chose the answer with a b inside - 1 b 214
or 2 b 755
. The former worked.
Publicspeakingisveryeasy.126241207201b2149opekmq426135
And it worked
There is a file called turtle
in the home directory of thor
which contains python turtle instructions. I need to build a python script to tokenize, parse and execute the turtle which may give me a graphical clue. The script is as follows.
As we can see, it spells out SLASH. I tried that passwork but it didnt work. I noticed the last time of the README, Can you digest the message? :)
which suggests an MD5 digest. I went ahead to do it with an online tool and I got this 646da671ca01bb5d84dbb5fb2238dc8e
.
I tried that as my password for the zaz
user and it worked
Here are the enumeration results
it suggested that there is a setuid and setgid binary. Which means that file will be executed as the owner, which is root. We have to find a way to execute whoami
inside the exploit_me
binary
Upon closer inspection of the exploit_me
binary, it reads the first argument, strcpy to some buffer and calls puts to print the read result.
I tried to put more characters to test for buffer overflow, turns out the program did buffer overflow (SEGFAULT). Which means this binary is vulnerable against a buffer overflow attack.
After watching this video and reading a bit of this book to get an idea on how this would work, my strategy is to :
I have made a python script that repeatedly print out a pattern of characters like so
The output looks like this
To pass our payload into the program in the gdb shell, i can do
To automate this, I made a .gdbinit. I also set up another tty for the debugging session
After strcpy
finishes executing, we can use info frame
to view the current stack frame info. Which also lets us see the return address of the saved EIP
EIP is at 0x37654136, which translates to 7eA6
, however, since the system stores register values using little endian, we need to reverse it to 6Ae7
. We do a lookup in the payload string, the section 6Ae7
is at position 140
. Which means we need to have a payload of length 140 to be able to manipulate the saved EIP
We will now change our payload code to verify this.
The screenshot below verifies that the saved eip is 0x42424242, which is "BBBB" - the 140th byte onwards.
The instruction we are looking for is JMP ESP
, we can do so by printing the instructions of the binary and searching for jmp using objdump --full-contents -D exploit_me | grep jmp
As we can see, we dont have the instruction we want to jump to. So we will proceed with the following step
The code we are trying to run is
Translated to assembly, it looks like
When assembled using this site, the corresponsing instructions will be "\x48\x31\xC0\x48\x31\xDB\x48\x31\xC9\x48\x31\xD2\x68\x6E\x2F\x73\x68\x68\x2F\x2F\x62\x69\x89\xE3\x50\x53\x50\xB0\x0B\xCD\x80"
. To output the byte literal, we can do so in python
print("\x48\x31\xC0\x48\x31\xDB\x48\x31\xC9\x48\x31\xD2\x68\x6E\x2F\x73\x68\x68\x2F\x2F\x62\x69\x89\xE3\x50\x53\x50\xB0\x0B\xCD\x80")
With that information, we can export the shellcode inside an environment variable
Now when we go back to GDB, we are able to see our environment variable in the stack and they are located waay below the EBP. I was able to inspect them using x/50s $esp+450
which prints stack content and I see the env var in address 0xbffff90c
and the shellcode should begin at address 0xBFFFF916
. Reverse it for little endianess and make it hex string literal, we get \x16\xf9\xff\xbf"
now our payload script looks like this
Here is how the address looks like in GDB
The code didnt work and I got some unexpected instructions when I jumped to my shellcode (shown below). turns out when I used the assembler tool, I did not specify the correct architecture (x64 instad of x86) and that same assembly that generated the opcode was different hence the weird instructions in the end.
Of course, I had to get the env pointer again
The shellcode.py file is changed to
print("\x31\xC0\x31\xDB\x31\xC9\x31\xD2\x68\x6E\x2F\x73\x68\x68\x2F\x2F\x62\x69\x89\xE3\x50\x53\x50\xB0\x0B\xCD\x80")
And payload.py is changed to
I tested the shellcode in GDB and it did seem that I managed to execute the shell command in that environment.
However, I get segfaults and invalid instructions if I try to launch it without GDB. It should not be the shellcode, so it might have something to do with the payload or the offset.
After some searching, I realized that GDB also adds environemt variables and we all have been building our exploit on the additional environment variables. Which might be causing our payload or offset to be incorrect.
The environment variables added are the LINES
and COLUMNS
variable, which is used by GDB internally to determine display dimensions. These variables DOES NOT exist if i launch it normally.
Hence, we need to regenerate the payload with a fresh env instead.
The new pointer to the shellcode
And the new payload
Once those changes are applies, we should be able to execute a shell as root.
Refer Path 1 on getting password for laurie
Once in the machine, I did uname -a
to determine the kernel version of the machine. The output is like so
I tried searching for any kernel exploits starting version 3.0 in exploitDB. Here are the results I found.
I tried using the mempodripper but it didnt work
Thus, I widen my search to start from version 2.0 instead
the first verified exploit with gcc is called dirty cow.
This expoit leverages the non-atomicity of the systems Copy on Write (COW) mechanism to allow us to write to files which we have read permissions only.
TLDR: the kernel has a mechanism in place to improve memory redundancy by creating a copy of data in a page if its shared across multiple resources whenever a request to write to that page is made.
However, the step which they locate the address page and write to the page is not atomic, which gives us space for race-condition attacks. There is also a safety mechanism in COW that will write to the original memory space instead if the copy is destroyed (like calling madvise on a mmap region).
With this information, our desired timing for a race condition will be
With that said, we can write things to files like /etc/passwd
to gain access to root.
Here is the exploit code from exploitDB
I followed the compilation steps, and I get root
Refer path 1 on getting password to zaz
My first step is to locate the address of the system()
libC function so I created a dummy.c with the contents like below
I then compile and launch the source with GDB and printed out the system
symbol information. The address of the system
function is 0xb7e6b060
After that, I created an env variable to store the string argument /bin/sh
for our system()
function. I also made a binary to ease the use of getting an address of a environment variable for us. The reason we also needed to provide the program name as argument when predicting the env address is because the program name affects the beginning of the envp pointer.
The way libC function gets called and reads arguments is through the contents in the stack and it looks like this
our BINSH variable is at 0xbfffff41
. After we get this information, we can construct a payload that
0xb7e6b060
BEEF
0xbfffff41
To sum it in a one liner, it looks something like this
And we are now root.
After using nmap to get information about services running which are facing to the web, I used gobuster to enumerate the directories which can be accessed.
Below is the enumeration for the HTTPS port
Below is the enumeration for the HTTP port
There are a few services we can access from the HTTPS endpoint, like /forum
, /phpmyadmin
and /webmail
. I first went to the forum to see what is it.
I was greeted with a reddit like forum like below, however I noticed an intresting topic regarding login failure
I did find a password-like string in the post, So im trying to use that password !q\]Ej?*5K5cy*AJ
to login to various users on the platform.
I used the password on user lmezard and I was able to login to his account on the forum.
I found his email address and I went to the webmail service to log in using that address and password; and I see some intresting stuff
I went to phpmyadmin and tried the credentials root/Fg-'kKXBj87E:aJ$
, and I am able to access the dashboard as root.
At this point, I have tried deciphering the passwords and whatnot, but I seem to fail to determine the exact encryption method of the passwords. But I stumbled upon this article that gave me directions on how to move forward.
As the article suggests, we can actually use the MYSQL executor in phpmyadmin to write create new files nad write content to them using SELECT INTO OUTFILE
, which is originally made to serve as a convinience tool to quickly parse sql results into files. However, we can also write our own content into the outfile as long as it does not get changed by the query itself.
And since the service is running in apache with php, which means we can access php files in the browser and it will execute the file to return the web content. With that said, the strategy is to execute something using the browser, and we can specify the things we want to execute with the SELECT INTO OUTFILE
on phpmyadmin.
For a proof of concept, we can try to execute this sql statement
We should be able to head to ipaddr/forum/whoami.php
and see the output of the command whoami
. But it turns out I dont have permissions to write to that folder.
I went to the source code for the forum page they are using and found out there are other directories like backups, config, images...
and turns out I can access the templates_c
directory
So i changed my script to write in the images directory instead
and I got the result when running the php file.
After some searching around with this command, I am able to get the password to the lmezard machine
Refer to part 1 for the rest of the steps
my ip to host from kali is 172.19.144.1
. cat /etc/resolv.conf
to get IP > thiscan work to host and wsl, but
Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)' -or $_.InterfaceAlias -eq 'vEthernet (Default Switch)'} | Set-NetIPInterface -Forwarding Enabled
-> this command works for when your VM is bridged. change last word to Disabled to remove the IP forwarding.
To get IP to vm, do nmap -sn 192.168.0.1/24
in KALI
Set vbox to host only, find the ip and subnet via ipconfig
Run nmap to scan for IPs
nmap -v -sn 192.168.56.1/24
reveal open ports
nmap -A [ip of the found host]
From earlier ISO enumeration by Jun Han, we can find this info
Seems like the version of the Linux kernel in the ISO is 3.2.0-91
while the version of Ubuntu is 12.04
After some googling, I discovered CVE, which is a system that provides a reference method for Common Vulnerabilities and Exposures
There are a total of 3826 Linux kernel related CVEs on this list
Filtering to only Privilege Escalation ones that are discovered after version 3.2, we're left with 15 CVEs: