c++异常处理绕过canary
基础知识感谢这位师傅的博客,然我茅塞顿开!! 原理c++中当某个函数throw某个exception时,程序便会从当前函数开始向上回溯调用链,直到找到匹配的catch,执行完catch后,便会接着在catch所在函数继续执行。 结论异常处理本身存在一些问题,并且使得canary这样的栈保护机制无效。因为异常抛出后的代码不会执行,自然也不会检测canary,自然也不会调用stack_check_fail(). 在此基础上我们发现了一些控制程序流的方式: 通过覆盖rbp,进而控制程序流走向。当然前提是栈帧的确使用rbp存储,因为一些情况下程序只依靠rsp增减。 通过覆盖ret地址,使异常被另外一个handler处理 在某些情况下还可以通过伪造覆盖类虚表的手法,使其在cleanup handler执行析构函数的时候劫持程序流(本文不做详细分析) 覆盖ret地址后,就会去执行ret地址的handler函数。前提是这个handler函数要能够匹配这样的异常。 例题羊城杯2024 logger ❯ checksec pwn[*] '/home/yang/pwn' Ar ...
pwn http:JarvisOJ HTTP
前置知识 popen()函数:开启新进程执行linux命令 htons()函数:程序监听端口 漏洞分析为了便于分析,我已经将相关函数重命令了。 主函数:标准的socket交互流程,在while循环中的handle函数中处理用户输入 void __fastcall __noreturn main(int a1, char **a2, char **a3){ struct sockaddr s; // [rsp+0h] [rbp-20h] BYREF __pid_t v4; // [rsp+14h] [rbp-Ch] int v5; // [rsp+18h] [rbp-8h] int fd; // [rsp+1Ch] [rbp-4h] signal(17, (__sighandler_t)handler); fd = socket(2, 1, 0); if ( fd < 0 ) { perror("socket"); exit(-1); } memset(&s, 0, sizeof(s)); ...
利用svcudp_replay实现apple2_orw
手法在apple2前提下,将chunkB调用函数填充为svcudp_replay+26,再调试定位leave ret和orw该写的位置。 例子题目地址:oneday 提取码: Ya0a 漏洞 UAF 只有一次show和edit ROPgadget --binary ~/ctf/tools/glibcallinone/libs/2.34-0ubuntu3_amd64/libc.so.6 --only 'lea|mov|call' | grep 'rdi, r13' 用这个命令去找magic_gadget,其中有0x000000000016cacd : mov rdi, r13 ; call qword ptr [rax + 0x28],注意是rax+0x28,然后gdb调试具体确认即可。 当然,如果有符号表的话,也可以直接在gdb中找到这段汇编: <svcudp_reply+26>: mov rbp,QWORD PTR [rdi+0x48]<svcudp_reply+30>: mov rax,QWORD PTR [rb ...
利用stdout泄露libc
手法原因:没有show函数。攻击思路:修改_IO_2_1_stdout_: 将_flags位修改为0xfbad1800 将_IO_write_base末尾字节修改为\x00 中间的变量_IO_read_ptr _IO_read_end _IO_read_base直接填充为0 p64(0xfbad1800)+p64(0)*3+'\x00' 后续程序在调用puts函数时,就会泄露出存在libc中的地址,我们找到对应的偏移就能得到libc基址。 例子题目地址: noleak 提取码: Ya0a 漏洞 strlen长度计算错误,造成堆溢出 构造堆块重叠 没有show 攻击_IO_2_1_stdout_泄露libc基址 思路 爆破攻击_IO_2_1_stdout_泄露libc基址 修改__malloc_hook为one_gadget 函数分析 expfrom pwn import *from pwn import p64,u64,p32,u32,p8from LibcSearcher import *context.terminal = ["tmux&qu ...
高版本off by null模版
新增加的保护2.29之后if (chunksize (p) != prev_size (next_chunk (p))) malloc_printerr ("corrupted size vs. prev_size"); 这会检查pre size和要合并的chunk_size是否相同;在这之前普通的off by null,我们只需要修改pre size和pre inuse就能完成堆块重叠。 方法申请8个堆块create(0x410)#0 Acreate(0x100)#1 #paddingcreate(0x430)#2 Bcreate(0x430)#3 Ccreate(0x100)#4 paddingcreate(0x480)#5 Hcreate(0x420)#6 Dcreate(0x100)#7 padding 我们要做的就是保证C堆块地址是00结尾; 利用地址残留,保存C的fd和bk指针free(0)free(3)free(6)free(2)payload=b'\x00'*0x430+p64(0)+p32(0x551)cre ...
house_of_apple2浅析
利用条件 泄露libc和heap地址 使用largebin attack控制_IO_list_all 能控制程序执行IO操作,包括但不限于:从main函数返回、调用exit函数 控制fakeio_file的vtable和_wide_date 使用 _flags设置为~(2 | 0x8 | 0x800),如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为 sh;,注意前面有两个空格 vtable设置为_IO_wfile_jumps/_IO_wfile_jumps_mmap/_IO_wfile_jumps_maybe_mmap地址(加减偏移),使其能成功调用_IO_wfile_overflow即可 _wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A _wide_data->_IO_write_base设置为0,即满足*(A + 0x18) = 0 _wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0 _wide_data->_wide_vtable设置为可控堆地址B,即满足* ...
house of water & TFCctf2024 mcguava
题目可以从 r3kapig 战队的比赛题库中找到:TFC CTF 2024(Jeopardy) (notion.site) 条件&效果前置条件: UAF 可以申请足够大的堆块 不需要泄露任何内存地址 实现效果:能够在tcache链表上留下libc的相关地址并将其申请出来。
movaps和movups
movaps作用:movaps 是 x86 汇编语言中的一个指令,用于处理 SIMD(Single Instruction, Multiple Data)寄存器中的浮点数据。它的主要功能是将对齐的128位浮点数据从一个位置移动到另一个位置。 要求栈16字节对齐 movupsmovups 是 x86 汇编语言中的一条指令,用于将128位浮点数据从一个位置移动到另一个位置。与 movaps 不同的是,movups 不要求数据是 16 字节对齐的,因此可以操作未对齐的数据。
orw进阶技巧
flag文件名未知getdentsgetdents 是 Linux 系统调用,用于读取目录的内容。与常用的高级文件操作函数(如 readdir)相比,getdents 提供了更底层的访问方式,它直接返回目录项的信息。这通常用于在需要更高性能或对系统调用进行更精细控制的场景中。 题目只能使用read open write close函数,和以下函数: gendents:用于目录遍历,可以用于绕过flag文件名未知情况。 mprotect:修改权限,用来绕过NX保护 exit_group:Linux独有的系统调用,调用后会使得进程的所有线程都退出。 使用 打开存有flag文件的目录:open("/home/ctf", 0),返回文件描述符为3 遍历目录:getdents(3, buf, 0x1000) 遍历3描述符中的内容,将文件名存在buf中,长度最大为0x1000字节。 打印所有文件名:使用write(1, buf, 0x1000),找到可能是flag的文件
覆盖.fini_array函数指针
函数说明.fini_array函数指针其实是一个数组指针,其中存有一系列函数指针,这些函数是main函数执行完后才会自动触发。同理,在.init_array中的函数是在main函数之前就触发,一般是用来初始化程序运行的条件。 我们的利用一般是覆盖.fini_array中函数指针,使main函数执行完后控制程序执行流到后门函数。 原理调试这里有一个test程序,用来看看.fini_array原理: #include <stdio.h>#include <stdlib.h>static void start(void) __attribute__ ((constructor));static void stop(void) __attribute__ ((destructor));int main(int argc, char *argv[]){printf("start == %p\n", start);printf("stop == %p\n", stop);return 0;}voidstart(vo ...
PolarCtf困难题系列pwn
choose漏洞解析 格式化字符串泄露canary leaklibc泄露libc 栈溢出+栈迁移到我们输入位置 libc由于题目没给libc(真难受),用LibcSearcher: expfrom pwn import *from pwn import p64,u64,p32,u32,p8from LibcSearcher import *context.terminal = ["tmux","sp","-h"]context(log_level="debug",os="linux",arch="amd64")io = remote("120.46.59.242",2107)# io = process("./pwn")elf=ELF("./pwn")sla = lambda x,y : io.sendlineafter(x,y)sa = lambda x,y : io.sendafter(x,y)sl ...
aarch64_ret2_libc
有关知识在aarch64中: X29相当于rbp寄存器。 X30寄存器中保存程序的返回地址,当ret时,会将X30中的地址给PC寄存器。 通过X0-X7寄存器传参。 ldr:Load Register(加载寄存器) ldr x0, [sp, #0x18] 这条指令的含义是将栈指针 (sp) 加上偏移量 0x18 所指向的内存地址中的数据加载到寄存器 x0 中。 ldr x0, [sp], #0x18 这条指令的含义是将栈指针 (sp) 所指向的内存地址中的数据加载到寄存器 x0 中,然后将sp增加偏移量 0x18。 本题泄露的got地址只有三字节,其实是“\x00”截断,需要我们加上0x4000000000。 分析 先泄露libc,再栈溢出ret2libc。 这里我们在ropper中找到一个gadget:ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret; 思路:将/bin/sh传给X0,将system传给X30。按照x64来说,我们会这样构造:prdi binsh system 但是这道题传参并不是紧紧邻接的。我们调试一下 ...