模拟退火算法
简介由于很多题的正解可能会有一点困难,而整个题的大致内容又可以抽象为找出某一个函数的最大/最小值时,就可以试着用模拟退火来解决。
假设有如下一段函数:
从O点出发,贪心的去查找函数的最低点,最终会陷入q点这个局部最优解而无法跳出去。而真正的最优解实际上是m点。
联系到物理上退火降温的过程,一个处于很高温度的物体,现在要给它降温,使物体内能降到最低。常规的思维就是让温度直接迅速降低,但实际上,过快地降温会使得物体来不及有序地收缩,难以形成内能最低的结晶态。正确的做法是徐徐降温,才能使得物体的每一个粒子都有足够的时间找到自己的最佳位置并紧密有序地排列。开始温度高的时候,粒子活跃地运动并逐渐找到一个合适的状态。在这过程中温度也会越降越低,温度低下来了,那么粒子也渐渐稳定下来,相较于以前不那么活跃了。这时候就可以慢慢形成最终稳定的结晶态了。(这一段话参考自大佬FlashHu的博客)
针对于上面那个函数图,在陷入q这个局部最优解时,我们让它以一定的概率去接受并不优于它的解,这样才能跳出局部的限制。而这个概率就是e^(△f/T)。T是当前温度,△f是当前点的函数值f(x)与目标点函数值f(x+△ ...
cmcc_simplerop
分析日常刷题。
checksec发现只开了Partial RELRO和NX,还是打ROP。
打开ida查看main函数。
读入了0x64个字节,显然有栈溢出。但是这个时候去看函数列表,发现这个程序貌似是直接把libc给dump下来了,所以应该没法利用ret2libc这一套,而且找不到system函数。
但是由于导入了很多函数,可供利用的gadget是很多的。所以可以试着用int 0x80来调用系统函数。
经过一番查找,这四个gadgets就够了。
12340x0806eeef # nop ; int 0x80 ; ret0x080bae06 # pop eax ; ret0x0806e851 # pop ecx ; pop ebx ; ret0x0806e82a # pop edx ; ret
栈上实际情况和ida分析的稍有不同,用gdb调出来v4与ebp的偏移
经过计算,偏移是0x1c,所以盖过ebp一共要0x20个垃圾数据。
我们getshell的思路肯定是execve(“/bin/sh”, 0, 0),一开始我是直接在.rodata段上找到了”sh”
但是不知为何用不了( ...
Heap-Basic
Basic管理heap的数据结构被称为Arena。
Linux早期版本采用dlmalloc作为默认的内存分配器,但是遇到多线程环境时,多个线程将共用同一个堆,因此临界区的竞争将会降低内存分配的效率。
而现在使用的ptmalloc(per thread malloc)对多线程的支持就很好(线程数<=CPU内核数时),每个线程都有一个自己的Arena。
主线程的arena叫做main_arena,他是一个静态全局变量,该arena的malloc_state存放在glibc的代码中。
main_arena对应的堆通过brk申请,子arena对应的堆则通过mmap申请。因此主Arena只有一个堆,而子Arena可以对应多个堆,当原来的堆不够用时,就会申请新的堆,然后和原来的堆链为一个链表。
malloc概述函数用法:
1void *ptr = malloc(size)
第一次申请内存需要通过syscall(glibc, OS, kernel三方沟通)来实现,此后都交由glibc实作的内存管理机制来管理。
第一次malloc的时候,如果要申请的内存小于128KB,就会用sys_brk来直 ...
ez_pz_hackover_2016
分析这是在buuctf上找的一道题,还是关于栈溢出的。
checksec查看保护,发现开了FULL RELRO(无lazy binding过程,got表不可写),但其他的都关了。
分析源码:
在chall函数里可以发现,如果s的内容和”crashme”相同,便可以进到vuln函数,将s的内容复制到vuln函数的dest里,从而造成溢出。由于字符串比较使用的是strcmp(),所以可以用’\x00’截断”crashme”,然后在后面写入payload。
gdb调试,查看内存空间,发现栈上的空间是可读可写可执行的,所以可以直接将shellcode写进去,然后劫持vuln函数的返回地址到shellcode上来getshell。
接下来要做的就是泄露出dest到ebp的距离,以及计算出写入的shellcode和chall函数里泄露出的那个栈上的地址的偏移量。在vuln函数的function epilogue之前那个nop上下断点,查看一下ebp和刚刚输入的”crashme”的位置
dest到ebp的偏移可以算出来是0x16,而shellcode的起始位置距离ebp是0x8的偏移(0x4盖 ...
pwn1-厦门邀请赛
分析拿到过后直接分析源码,发现read处存在溢出。
checksec一下,发现除了PIE以外的保护都开了,所以需要想办法泄露canary。
如图所示可以看出,canary被放到了rbp-8的位置(通常都是这里),此时再查看一下main函数的栈,是可以发现read()可以将垃圾数据盖到canary前面,然后利用puts()打印出来。(canary最低位一定是’\x00’,它会打断puts函数的输出,所以这里我们使用sendline(),可以多塞一个’\r’过去,刚好盖掉’\x00’,到时候再补上这个’\x00’就好了。)
如此一来,canary就会被泄露了。但是接下来要思考的是,如何获得shell。分析binary之后发现没有什么好利用的东西,所以去找libc附件上的gadget。
果然,存在one_gadget去执行shell程序。0x45216这个只需要保证$rax为空就好了,用起来最方便。libc附件是开了PIE保护的,所以需要我们先泄露出它的基址,然后再getshell。剩下的就没什么好说的了。
exp123456789101112131415161718192021222 ...
利用__libc_csu_init的通用gadgets
简介在__libc_csu_init中有以下gadgets,可以帮助我们摆好很多寄存器,或者用来花式rop。
1234mov rdx, r13mov rsi, r14mov edi, r15dcall qword ptr [r12+rbx*8]
恰好能让rdx和rsi的值被r13和r14控制,而且若能让rbx为0, r12可以调用特定的shellcode,
一般拿来充当ret,找到ROP下一句的位置填进去
而刚好还有如下gadgets
1234567pop rbxpop rbppop r12pop r13pop r14pop r15ret
例题ciscn_s_3分析
发现vul()是在执行一个read(0, [rsp+buf], 0x400)和write(1, [rsp+buf], 0x30)
读入了0x400个数据显然有缓冲区溢出。
checksec发现只开了NX。
发现gadgets()中存在
mov rax, 0xf ; ret;和mov rax, 0x3b ; ret;
查阅资料得知0x3b是execve()的系统调用号,而vul()中刚好有sy ...
PWN BASIC
一些指令objdump -d -M intel (文件名) #查看汇编源码(加intel是想看ASM版本的,默认是AT&T)
readelf -a (文件名) #查看elf文件头信息等
ldd (文件名) #看binary链接到了哪些函数库
nano /root/.gdbinit #同时安装了pwndbg和peda,在这里面注释切换
ps -a #查看所有进程,找到目标进程,在gdb里用attach + 进程id调试
#与之配合的,可以在exp相应位置加个空的i ...
GDB BASIC
指令miscdisas (函数名) #在gdb里反汇编某函数,查看某句指令的地址,好下断点
vm(virtual memory)
at [进程id] #连接到目标进程调试
b (num) #在num行下断点,或者加一个地址,在目标地址下断点
r #重新运行文件
start #单步执行,运行程序,停在第一执行语句
next或n #单步调试(逐过程,不进入函数)
step或s #单步调试(逐语句,会进入函数)
finish #跑完这个函 ...
XCTF 3rd-RCTF-2017 Recho
分析主程序可以看出,就是一直读一个字符串,转换成长度过后用read()读这么多个数据。
长度在小于16的时候会变成16,但是没有上限检查。
checksec发现只开了nx,所以思路应该是打rop。
查看一下字符串
发现了”flag”, 所以可以尝试用open读flag文件,然后read写到内存上,再用printf打印出来。
寻找通用gadget的时候
12345pop rdi ; retpop rdx ; retpop rax ; ret
都能找到,但是要控制第二个参数rsi,就只找到了
pop rsi ; pop r15 ; ret
这里就将就着用了。
read和printf是程序自带的,但是open就需要我们自己构造了。
gdb动态调试的时候反汇编一下alarm函数
发现了syscall可以利用。和alarm有0x5的偏移,可以尝试一下got表劫持。
经过一番寻找,发现一个比较方便的gadget,会让rdi存的值所在的地址的值加上rax寄存器低8位的值
0x000000000040070d : add byte ptr [rdi], al ; ret
而这个时候只需要用po ...
RCTF-2015 welpwn
分析直接打开ida x64分析源码
发现读了0x400个数据到buf里,刚好没法溢出。于是再查看一下echo函数。
这个for循环特别可疑,会把之前main函数读到的数据赋给s2,直到到有\x00才会停下来。所以这里是一个溢出点。但是我们在覆盖返回地址的时候,肯定会有\x00在里面,所以这里我们最多只能使用一个gadget,剩下的部分就会被截断了。
一开始思路到这里就断了。但是再仔细分析main函数,不难发现buf的起始位置是main函数一开始rsp的位置。好家伙,这下有意思了,s2的起始位置到buf的起始位置起始只隔了0x20!
payload送上去之后,前0x18个位置是不能出现\x00的,接下来0x8可以是一个gadget,再之后就遇上了buf,也就是又会是那0x18个垃圾字符,以及这个gadget。
基于这个特殊的结构,这时就有一种思路了:有没有可能,让前面s2那里的数据和buf的数据能刚好接上,并且只使用一个gadget?答案是有的。用__libc_csu_init上面的pop指令:
0x000000000040089e : pop r13 ; pop r14 ; pop ...