├── requirements.txt ├── LICENSE ├── README_CN.md ├── README.md ├── __update__.py ├── Excalibur2-help.txt ├── Excalibur2.py └── __init__.py /requirements.txt: -------------------------------------------------------------------------------- 1 | pwn 2 | LibcSearcher 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 lmarch2 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 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # Excalibur2 2 | 3 | ## Description 4 | 5 | 一个打pwn的ctfer的简单集成库 6 | 7 | 本Python库收录了常见的PWN题函数,旨在简化pwn题中脚本编写的过程呢个,帮助广大pwner节约时间,提高解题效率 8 | 9 | 十分欢迎各位师傅使用Excalibur,同时欢迎对鄙人的代码提出意见和指导 10 | 11 | ## Install 12 | 13 | 安装 14 | 15 | > pip3 install Excalibur2 16 | 17 | 检查是否有更新版本 18 | 19 | > python3 -m Excalibur2.\_\_update\_\_ 20 | 21 | 更新 22 | 23 | > pip3 install Excalibur2 --upgrade 24 | 25 | ## Help 26 | 27 | Python内置帮助 28 | 29 | > python3 -m pydoc Excalibur2 30 | 31 | > 查看帮助文档 32 | > 33 | > `import Excalibur2` 34 | > 35 | > `help(Excalibur2)` 36 | > 37 | > 查看函数帮助 38 | > 39 | > `from Excalibur2 import *` 40 | > 41 | > `help(function)` 42 | 43 | more details Please visit https://lmarch2.top/posts/8c945bd4/ 44 | 45 | ## Release 46 | 47 | ### 2.4, Feb 8, 2024 48 | 49 | contextset更名为setcontext 50 | 新增prhl函数 51 | proc默认参数设置为./pwn 52 | 添加自动计算有基址的地址 53 | 修复了csu和ropgadget函数bug 54 | 修改部分alias 55 | 翻译成英文,txt格式 56 | 57 | ### 2.2, Feb 8, 2024 58 | 59 | 修复了一些由包名称引起的问题 60 | 61 | ### 2.1, Feb 8, 2024 62 | 63 | 支持自定义调试终端,添加检查更新功能 64 | 65 | ### 2.0, Feb 8, 2024 66 | 67 | 本包诞生之日 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Excalibur2 2 | 3 | ## Description 4 | 5 | A simple integrated library for CTFers specializing in PWN challenges. 6 | 7 | This Python library includes common functions used in PWN challenges, aiming to simplify the process of exp for PWN challenges, helping pwners save time and improve efficiency in solving problems. 8 | 9 | We warmly welcome all masters to use Excalibur, and we also welcome feedback and guidance on our code. 10 | 11 | ## Install 12 | 13 | Install Excalibur2 by 14 | 15 | > pip3 install Excalibur2 16 | 17 | check for updates 18 | 19 | > python3 -m Excalibur2.\_\_update\_\_ 20 | 21 | update package 22 | 23 | > pip3 install Excalibur2 --upgrade 24 | 25 | ## Help 26 | 27 | python built-in help 28 | 29 | > check help documention 30 | > 31 | > `import Excalibur2` 32 | > 33 | > `help(Excalibur2)` 34 | > 35 | > check help for func 36 | > 37 | > `from Excalibur2 import *` 38 | > 39 | > `help(function)` 40 | 41 | more details Please visit https://lmarch2.top/posts/8c945bd4/ 42 | 43 | ## Release 44 | 45 | ### 2.4,Feb 8, 2024 46 | 47 | Renamed `contextset` to `setcontext`. 48 | Added a new function `prhl`. 49 | Set the default parameter for `proc` to `./pwn`. 50 | Added automatic address calculation for base addresses. 51 | Fixed bugs in the `csu` and `ropgadget` functions. 52 | Modified some aliases. 53 | 54 | ### 2.2, Feb 8, 2024 55 | 56 | Fix some bugs due to uncorrect package name 57 | 58 | ### 2.1, Feb 8, 2024 59 | 60 | Support custom debugging terminal and add check update function 61 | 62 | ### 2.0, Feb 8, 2024 63 | 64 | The birthday of the package 65 | 66 | -------------------------------------------------------------------------------- /__update__.py: -------------------------------------------------------------------------------- 1 | import requests.exceptions 2 | 3 | def _update(): 4 | welcome = ''' 5 | # /$$$$$$$$ /$$ /$$ /$$ 6 | # | $$_____/ | $$|__/| $$ 7 | # | $$ /$$ /$$ /$$$$$$$ /$$$$$$ | $$ /$$| $$$$$$$ /$$ /$$ /$$$$$$ 8 | # | $$$$$ | $$ /$$/ /$$_____/ |____ $$| $$| $$| $$__ $$| $$ | $$ /$$__ $$ 9 | # | $$__/ \ $$$$/ | $$ /$$$$$$$| $$| $$| $$ \ $$| $$ | $$| $$ \__/ 10 | # $$ >$$ $$ | $$ /$$__ $$| $$| $$| $$ | $$| $$ | $$| $$ 11 | # | $$$$$$$$ /$$/\ $$| $$$$$$$| $$$$$$$| $$| $$| $$$$$$$/| $$$$$$/| $$ 12 | # |________/|__/ \__/ \_______/ \_______/|__/|__/|_______/ \______/ |__/ 13 | 14 | Welcome to Excalibur ! 15 | ''' 16 | print(welcome) 17 | print('checking for updates...') 18 | 19 | import subprocess 20 | import sys 21 | import requests 22 | from bs4 import BeautifulSoup 23 | 24 | try: 25 | # 获取最新版本信息 26 | # 发送 GET 请求,并设置超时时间为 10 秒 27 | url = "https://pypi.org/project/Excalibur2/#history" 28 | response = requests.get(url, timeout=10) 29 | 30 | # 检查响应状态码 31 | if response.status_code == 200: 32 | # 使用 BeautifulSoup 解析 HTML 33 | soup = BeautifulSoup(response.text, "html.parser") 34 | 35 | # 查找所有包含版本信息和日期的标签 36 | version_tags = soup.find_all("a", class_="card release__card") 37 | if version_tags: 38 | flag = 0 39 | for version_tag in version_tags: 40 | version_info = version_tag.find("p", class_="release__version").text.strip() 41 | version_date = version_tag.find("time").text.strip() 42 | if flag == 0: 43 | latest_version = version_info 44 | flag += 1 45 | else: 46 | print("未找到版本信息") 47 | else: 48 | print("请求失败:", response.status_code) 49 | 50 | try: 51 | # 运行 pip show 命令来获取已安装库的版本信息 52 | result = subprocess.run(["pip", "show", "Excalibur2"], capture_output=True, text=True) 53 | installed_version = None 54 | for line in result.stdout.split("\n"): 55 | if line.startswith("Version:"): 56 | installed_version = line.split(":")[1].strip() 57 | break 58 | 59 | # 检查版本是否一致,如果不一致则提示更新 60 | if installed_version != latest_version: 61 | print('\033[93m'+f"WARNING: Your version of Excalibur2 ({installed_version}) is outdated. Please update to version {latest_version}."+'\033[0m') 62 | else: 63 | print('\033[92m'+'The Version is latest'+'\033[0m') 64 | except Exception as e: 65 | print('\033[91m'+f"Error checking for updates: {e}"+'\033[0m') 66 | except requests.exceptions.Timeout or requests.exceptions.ConnectionError: 67 | print('\033[93m'+"WARNING: Network connection timed out. Please check your internet connection."+'\033[0m') 68 | 69 | 70 | if __name__ == "__main__": 71 | _update() 72 | -------------------------------------------------------------------------------- /Excalibur2-help.txt: -------------------------------------------------------------------------------- 1 | Help on package Excalibur2: 2 | 3 | NAME 4 | Excalibur2 5 | 6 | DESCRIPTION 7 | This module provides functionality for ctf pwn. 8 | Including some common operations in learning and competitions 9 | 10 | Welcome all masters to provide advice on the code 11 | Please visit https://lmarch2.top/posts/8c945bd4/ for code details 12 | 13 | -------------------------------------- 14 | Excalibur -- Sword of Contract Victory 15 | -------------------------------------- 16 | 17 | Example: 18 | >>> from Excalibur2 import* 19 | 20 | PACKAGE CONTENTS 21 | Excalibur2 22 | __update__ 23 | 24 | FUNCTIONS 25 | POINTER(...) 26 | 27 | ROPgadget(bin, order=None, gr='', option='') 28 | ------ 29 | Descriptions 30 | find gadgets you want using ROPgadget 31 | 使用ROPgadget找到想要的gadget 32 | 33 | ------ 34 | Parameters 35 | bin : binary file 36 | order : gadget you want 37 | gr : using grep (1) or not (0) 38 | option : to find a string 39 | 40 | ------ 41 | Returns 42 | gadget 43 | 44 | addressof(...) 45 | addressof(C instance) -> integer 46 | Return the address of the C instance internal buffer 47 | 48 | alignment(...) 49 | alignment(C type) -> integer 50 | alignment(C instance) -> integer 51 | Return the alignment requirements of a C instance 52 | 53 | byref(...) 54 | byref(C instance[, offset=0]) -> byref-object 55 | Return a pointer lookalike to a C instance, only usable 56 | as function argument 57 | 58 | cl lambda (...) 59 | # close() 60 | 61 | csu(csu_end_addr=0, csu_front_addr=0, r12=0, r13=0, r14=0, r15=0, rbx=0, rbp=1, last=None) 62 | ------ 63 | Descriptions 64 | ret2csu utilizes rop chain 65 | ret2csu利用rop链 66 | # pop rbx,rbp,r12,r13,r14,r15 67 | # rbx should be 0, 68 | # rbp should be 1,enable not to jump 69 | # r15 should be the function we want to call 70 | # rdi=edi=r12d 71 | # rsi=r13 72 | # rdx=r14 73 | 74 | ------ 75 | Parameters 76 | rbx, rbp, r12, r13, r14, r15 : registers 77 | csu_end_addr,csu_front_addr, last : gadgets 78 | 79 | ------ 80 | Returns 81 | payload 82 | 83 | debug(c=0) 84 | ------ 85 | Descriptions 86 | debug 87 | To use gdb debugging, please use the command line parameter G, such as: python3 exp.py G 88 | 调试 89 | 若要使用gdb调试,请使用命令行参数G,如:python3 exp.py G 90 | 91 | ------ 92 | Parameters 93 | c : gdb attach上进程之后执行的命令字符串 (0) 94 | 95 | ------ 96 | Returns 97 | None 98 | 99 | default(mode) 100 | 101 | el(arg='pwn') 102 | ------ 103 | Descriptions 104 | load elf, default filename pwn 105 | 加载elf,默认文件名是pwn 106 | 107 | ------ 108 | Parameters 109 | arg : the path of elf 110 | 111 | ------ 112 | Returns 113 | None 114 | 115 | elsym(add) 116 | ------ 117 | Descriptions 118 | set elfbase for binary 119 | 基址和偏移相加得到真实地址 120 | 121 | ------ 122 | Parameters 123 | add : the addr needed to be added 124 | 125 | ------ 126 | Returns 127 | elfbase + add 128 | 129 | fmt(offset, begin, end, size, written) 130 | ------ 131 | Descriptions 132 | fmt attack 133 | fmt攻击 134 | 135 | ------ 136 | Parameters 137 | offset : fmt 偏移 138 | begin : 将要被写入的地址 139 | end : 将要写入的地址 140 | size : 写入的格式化字符串形式 141 | wriiten : printf函数已写入的字节数 142 | 143 | ------ 144 | Returns 145 | payload 146 | 147 | elfbase + add 148 | # offset(int) - 您控制的第一个格式化程序的偏移量 149 | # 字典(dict) - 被写入地址对应->写入的数据,可多个对应{addr: value, addr2: value2} 150 | # numbwritten(int) - printf函数已写入的字节数 151 | # write_size(str) - 必须是byte,short或int。告诉您是否要逐字节写入,短按short或int(hhn,hn或n) 152 | 153 | get_addr32() 154 | ------ 155 | Descriptions 156 | Receive leaked 32-bit libc address 157 | 接收泄露的32位libc地址 158 | 159 | ------ 160 | Parameters 161 | None 162 | 163 | ------ 164 | Returns 165 | recieved addr 166 | 167 | get_addr64() 168 | ------ 169 | Descriptions 170 | Receive leaked 64-bit libc address 171 | 接收泄露的64位libc地址 172 | 173 | ------ 174 | Parameters 175 | None 176 | 177 | ------ 178 | Returns 179 | recieved addr 180 | 181 | get_errno(...) 182 | 183 | gf lambda (...) 184 | # getflag 185 | 186 | got(fun, *pie_base) 187 | ------ 188 | Descriptions 189 | Binary file function got address offset 190 | 二进制文件函数got表地址偏移 191 | 192 | ------ 193 | Parameters 194 | fun : function name 195 | pie_base (optional) : the binary base when pie enabled 196 | 197 | ------ 198 | Returns 199 | got addr of func 200 | 201 | ia lambda (...) 202 | # interactive() 203 | 204 | int16 lambda data 205 | # int(data,16) 206 | 207 | lg lambda name, addr 208 | # log.success(name+'='+hex(addr)) 209 | 210 | lib(arg='/usr/lib/x86_64-linux-gnu/libc.so.6') 211 | ------ 212 | Descriptions 213 | load libc, default local system libc 214 | 加载libc,默认本地系统libc 215 | 216 | ------ 217 | Parameters 218 | arg : the path of libc 219 | 220 | ------ 221 | Returns 222 | None 223 | 224 | libcsym(fun, off=0) 225 | ------ 226 | Descriptions 227 | libc function address offset 228 | libc文件函数地址偏移 229 | 用于计算一两个libc函数地址时比较方便 230 | 231 | ------ 232 | Parameters 233 | fun : function name 234 | off (optional) : the libc base when pie enabled 235 | 236 | ------ 237 | Returns 238 | addr of libc func 239 | 240 | lisym(add) 241 | ------ 242 | Descriptions 243 | set elfbase for binary 244 | 基址和偏移相加得到真实地址 245 | 246 | ------ 247 | Parameters 248 | add : the addr needed to be added 249 | 250 | ------ 251 | Returns 252 | libcbase + add 253 | 254 | pack(...) 255 | pack(format, v1, v2, ...) -> bytes 256 | 257 | Return a bytes object containing the values v1, v2, ... packed according 258 | to the format string. See help(struct) for more on format strings. 259 | 260 | plt(fun, *pie_base) 261 | ------ 262 | Descriptions 263 | Binary file function plt address offset 264 | 二进制文件函数plt表地址偏移 265 | 266 | ------ 267 | Parameters 268 | fun : function name 269 | pie_base (optional) : the binary base when pie enabled 270 | 271 | ------ 272 | Returns 273 | plt addr of func 274 | 275 | pointer(...) 276 | 277 | pr(addr) 278 | print abbreviation 279 | 打印 280 | 281 | prb(data) 282 | ------ 283 | Descriptions 284 | print raw bytes without escaping 285 | 不转义打印原始字符串 286 | 287 | ------ 288 | Parameters 289 | data : the data you want to print 290 | 291 | ------ 292 | Returns 293 | None 294 | 295 | prh(addr) 296 | print Hexadecimal data abbreviation 297 | 打印十六进制 298 | 299 | prhl(addr) 300 | print length of data abbreviation 301 | 打印数据长度 302 | 303 | prl(addr) 304 | print length of data abbreviation 305 | 打印数据长度 306 | 307 | proc(bin='./pwn') 308 | ------ 309 | Descriptions 310 | load binary when no command line parameter R provided 311 | 没有命令行参数R时加载二进制文件 312 | 313 | ------ 314 | Parameters 315 | bin : the path of binary 316 | 317 | ------ 318 | Returns 319 | p 320 | 321 | rc lambda data=None 322 | # recv() 323 | 324 | remo(ip, port='') 325 | ------ 326 | Descriptions 327 | connect to remote when command line parameter R provided 328 | 有命令行参数R时连接到远程 329 | 330 | ------ 331 | Parameters 332 | ip : ip of remote 333 | port: port of remote 334 | using remo(ip) when given ip = ip:port or ip = ip port 335 | using remo(ip,port) when given ip and port 336 | 337 | ------ 338 | Returns 339 | p 340 | 341 | resize(...) 342 | Resize the memory buffer of a ctypes instance 343 | 344 | ru lambda delims, drop=True 345 | # recvuntil(delims,drop) 346 | 347 | sd lambda data 348 | # send(data) 349 | 350 | sda lambda delim, data 351 | # sendafter(delim,data) 352 | 353 | searchlibc(fun, real_addr, mode=1, offset=0) 354 | ------ 355 | Descriptions 356 | Determine the libc version from the leaked function real address and return /bin/sh string address and system function address 357 | 由泄露的函数真实地址确定libc版本,并返回/bin/sh字符串地址和system函数地址 358 | 359 | ------ 360 | Parameters 361 | fun : function name 362 | real_addr =: leaked real addr of func 363 | mode : flag of using libc (1) or libcsearcher (0) 364 | offset : the offset between leaked addr and base addr of func 365 | 366 | ------ 367 | Returns 368 | binsh, system 369 | 370 | set_errno(...) 371 | 372 | setbase(add) 373 | ------ 374 | Descriptions 375 | Add the base address and offset to get the real address 376 | 给二进制文件设置基址 377 | 378 | ------ 379 | Parameters 380 | add : the base addr of binary 381 | 382 | ------ 383 | Returns 384 | None 385 | 386 | setcontext(ar=64, de=1) 387 | ------ 388 | Descriptions 389 | set your structure and debug mode 390 | 设置文件架构和调试模式 391 | 392 | ------ 393 | Parameters 394 | ar : choose arch for amd64 (64) or i386 (32) 395 | de : using debug mode (1) or not (0) 396 | 397 | ------ 398 | Returns 399 | None 400 | 401 | setlibcbase(add) 402 | ------ 403 | Descriptions 404 | Add the base address and offset to get the real address 405 | 给libc设置基址 406 | 407 | ------ 408 | Parameters 409 | add : the base addr of binary 410 | 411 | ------ 412 | Returns 413 | None 414 | 415 | setterminal(termin='tmux', *args) 416 | ------ 417 | Descriptions 418 | set debug terminal 419 | 设置调试终端 420 | 421 | ------ 422 | Parameters 423 | termin : debug terminal (default tmux) 424 | args (optional) : context.terminal = [termin,args] 425 | 426 | ------ 427 | Returns 428 | None 429 | 430 | sizeof(...) 431 | sizeof(C type) -> integer 432 | sizeof(C instance) -> integer 433 | Return the size in bytes of a C instance 434 | 435 | sl lambda data 436 | # sendline(data) 437 | 438 | sla lambda delim, data 439 | # sendlineafter(delim,data) 440 | 441 | sym(fun, *pie_base) 442 | ------ 443 | Descriptions 444 | Binary file function address offset 445 | 二进制文件函数地址偏移 446 | 447 | ------ 448 | Parameters 449 | fun : function name 450 | pie_base (optional) : the binary base when pie enabled 451 | 452 | ------ 453 | Returns 454 | addr of func 455 | 456 | uu32 lambda data 457 | # u32(data.ljust(4,b'\x00')) 458 | 459 | uu64 lambda data 460 | # u64(data.ljust(8,b'\x00')) 461 | 462 | DATA 463 | API_FIND = 'https://libc.rip/api/find' 464 | API_LIBC = 'https://libc.rip/api/libc/' 465 | DEFAULT_MODE = 0 466 | GB = 1000000000 467 | GiB = 1073741824 468 | HEADERS = {'Content-Type': 'application/json'} 469 | KB = 1000 470 | KiB = 1024 471 | MB = 1000000 472 | MiB = 1048576 473 | PIPE = -1 474 | PTY = 475 | RTLD_GLOBAL = 256 476 | RTLD_LOCAL = 0 477 | STDOUT = -2 478 | absolute_import = _Feature((2, 5, 0, 'alpha', 1), (3, 0, 0, 'alpha', 0... 479 | arg_doc = {'p': 'number (int): Number to convert', 'u': 'data (bytes):... 480 | args = PwnlibArgs(, {}) 481 | cdll = 482 | context = ContextType() 483 | cyclic_pregen = b'' 484 | de_bruijn_gen = .db> 485 | default_style = {'00': functools.partial( 491 | memmove = 492 | memset = 493 | op_verbs = {'p': 'pack', 'u': 'unpack'} 494 | ops = ['p', 'u'] 495 | pydll = 496 | pythonapi = 497 | return_types = {'p': 'bytes', 'u': 'int'} 498 | rv_doc = {'p': 'The packed number as a byte string', 'u': 'The unpacke... 499 | signs = ['s', 'u'] 500 | sizes = {8: 'b', 16: 'h', 32: 'i', 64: 'q'} 501 | variables = {0: {'name': 'flags', 'size': 0}, 1: {'name': '_IO_read_pt... 502 | version = '4.12.0' 503 | 504 | FILE 505 | /home/lctfer/.local/lib/python3.10/site-packages/Excalibur2/__init__.py 506 | 507 | 508 | -------------------------------------------------------------------------------- /Excalibur2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | This module provides functionality for ctf pwn. 4 | Including some common operations in learning and competitions 5 | 6 | Welcome all masters to provide advice on the code 7 | Please visit https://lmarch2.top/posts/8c945bd4/ for code details 8 | 9 | -------------------------------------- 10 | Excalibur -- Sword of Contract Victory 11 | -------------------------------------- 12 | 13 | Example: 14 | >>> from Excalibur2 import* 15 | """ 16 | 17 | 18 | # Excalibur 19 | 20 | 21 | #----------------------------------------------------------------------------------------- 22 | # Packages 23 | #----------------------------------------------------------------------------------------- 24 | 25 | 26 | from pwn import * 27 | import os 28 | from struct import pack 29 | from ctypes import * 30 | import base64 31 | import click 32 | from LibcSearcher import * 33 | 34 | 35 | #----------------------------------------------------------------------------------------- 36 | # Settings 37 | #----------------------------------------------------------------------------------------- 38 | 39 | elfbase = 0 40 | libcbase = 0 41 | 42 | 43 | def default(mode): 44 | if mode == 'm': 45 | setterminal("tmux","new-window") 46 | setcontext() 47 | elif mode == 'h': 48 | setterminal("tmux","splitw","-h") 49 | setcontext() 50 | 51 | 52 | # Set up debugging terminal (especially efficient on WSL2) 53 | # 如何在WSL2上使用tmux调试请看https://lmarch2.top/posts/19b7c9d1/ 54 | def setterminal(termin='tmux',*args): 55 | ''' 56 | ------ 57 | Descriptions 58 | set debug terminal 59 | 设置调试终端 60 | 61 | ------ 62 | Parameters 63 | termin : debug terminal (default tmux) 64 | args (optional) : context.terminal = [termin,args] 65 | 66 | ------ 67 | Returns 68 | None 69 | ''' 70 | if(len(args)<=0): 71 | context.terminal = [termin, 'splitw', '-h'] 72 | else: 73 | context.terminal = [termin,*args] 74 | 75 | def setcontext(ar = 64, de = 1): 76 | ''' 77 | ------ 78 | Descriptions 79 | set your structure and debug mode 80 | 设置文件架构和调试模式 81 | 82 | ------ 83 | Parameters 84 | ar : choose arch for amd64 (64) or i386 (32) 85 | de : using debug mode (1) or not (0) 86 | 87 | ------ 88 | Returns 89 | None 90 | ''' 91 | if ar == 32: 92 | if de == 0: 93 | context(os='linux', arch='i386') 94 | else: 95 | context(log_level='debug', os='linux', arch='i386') 96 | else: 97 | if de == 0: 98 | context(os='linux', arch='amd64') 99 | else: 100 | context(os='linux', arch='amd64', log_level='debug') 101 | 102 | def debug(c = 0): 103 | ''' 104 | ------ 105 | Descriptions 106 | debug 107 | To use gdb debugging, please use the command line parameter G, such as: python3 exp.py G 108 | 调试 109 | 若要使用gdb调试,请使用命令行参数G,如:python3 exp.py G 110 | 111 | ------ 112 | Parameters 113 | c : gdb attach上进程之后执行的命令字符串 (0) 114 | 115 | ------ 116 | Returns 117 | None 118 | ''' 119 | if args.G: 120 | if(c): 121 | gdb.attach(p, c) 122 | else: 123 | gdb.attach(p) 124 | #pause() 125 | 126 | def prb(data): 127 | ''' 128 | ------ 129 | Descriptions 130 | print raw bytes without escaping 131 | 不转义打印原始字符串 132 | 133 | ------ 134 | Parameters 135 | data : the data you want to print 136 | 137 | ------ 138 | Returns 139 | None 140 | ''' 141 | for byte in data: 142 | print(f"\\x{byte:02x}", end="") 143 | print() 144 | 145 | def pr(addr) : 146 | '''print abbreviation 147 | 打印''' 148 | print(addr) 149 | 150 | def prh(addr) : 151 | '''print Hexadecimal data abbreviation 152 | 打印十六进制''' 153 | print(hex(addr)) 154 | 155 | def prl(addr) : 156 | '''print length of data abbreviation 157 | 打印数据长度''' 158 | print(len(addr)) 159 | 160 | def prhl(addr) : 161 | '''print length of data abbreviation 162 | 打印数据长度''' 163 | print(hex(len(addr))) 164 | 165 | def lib(arg = '/usr/lib/x86_64-linux-gnu/libc.so.6') : 166 | ''' 167 | ------ 168 | Descriptions 169 | load libc, default local system libc 170 | 加载libc,默认本地系统libc 171 | 172 | ------ 173 | Parameters 174 | arg : the path of libc 175 | 176 | ------ 177 | Returns 178 | None 179 | ''' 180 | global libc 181 | libc = ELF(arg) 182 | def el(arg='pwn') : 183 | ''' 184 | ------ 185 | Descriptions 186 | load elf, default filename pwn 187 | 加载elf,默认文件名是pwn 188 | 189 | ------ 190 | Parameters 191 | arg : the path of elf 192 | 193 | ------ 194 | Returns 195 | None 196 | ''' 197 | global elf 198 | elf = ELF(arg) 199 | def proc(bin="./pwn") : 200 | ''' 201 | ------ 202 | Descriptions 203 | load binary when no command line parameter R provided 204 | 没有命令行参数R时加载二进制文件 205 | 206 | ------ 207 | Parameters 208 | bin : the path of binary 209 | 210 | ------ 211 | Returns 212 | p 213 | ''' 214 | if not args.R: 215 | global p 216 | p = process(bin) 217 | return p 218 | 219 | def remo(ip,port='') : 220 | ''' 221 | ------ 222 | Descriptions 223 | connect to remote when command line parameter R provided 224 | 有命令行参数R时连接到远程 225 | 226 | ------ 227 | Parameters 228 | ip : ip of remote 229 | port: port of remote 230 | using remo(ip) when given ip = ip:port or ip = ip port 231 | using remo(ip,port) when given ip and port 232 | 233 | ------ 234 | Returns 235 | p 236 | ''' 237 | if args.R: 238 | global p 239 | if ' ' in ip : 240 | ip_port = ip.split(' ') 241 | p = remote(ip_port[0],ip_port[1]) 242 | elif not ':' in ip : 243 | p = remote(ip,port) 244 | else: 245 | ip_port = ip.split(':') 246 | p = remote(ip_port[0],ip_port[1]) 247 | return p 248 | 249 | def get_addr64() : 250 | ''' 251 | ------ 252 | Descriptions 253 | Receive leaked 64-bit libc address 254 | 接收泄露的64位libc地址 255 | 256 | ------ 257 | Parameters 258 | None 259 | 260 | ------ 261 | Returns 262 | recieved addr 263 | ''' 264 | recvaddr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) 265 | print("\n>>>> The leaked addr is ",hex(recvaddr),'\n') 266 | return recvaddr 267 | 268 | def get_addr32() : 269 | ''' 270 | ------ 271 | Descriptions 272 | Receive leaked 32-bit libc address 273 | 接收泄露的32位libc地址 274 | 275 | ------ 276 | Parameters 277 | None 278 | 279 | ------ 280 | Returns 281 | recieved addr 282 | ''' 283 | recvaddr = u32(p.recvuntil(b'\xf7')[-4:]) 284 | print("\n>>>> The leaked addr is ",hex(recvaddr),'\n') 285 | return recvaddr 286 | 287 | def sym(fun,*pie_base) : 288 | ''' 289 | ------ 290 | Descriptions 291 | Binary file function address offset 292 | 二进制文件函数地址偏移 293 | 294 | ------ 295 | Parameters 296 | fun : function name 297 | pie_base (optional) : the binary base when pie enabled 298 | 299 | ------ 300 | Returns 301 | addr of func 302 | ''' 303 | global elfbase 304 | if elfbase != 0: 305 | pie_base = elfbase 306 | if(len(pie_base)<=0): 307 | addr = elf.sym[fun] 308 | print("\n>>>> The ",fun," offset is ",hex(addr),'\n') 309 | return addr 310 | else : 311 | addr = elf.sym[fun]+pie_base 312 | print("\n>>>> pie_base ",pie_base,'\n') 313 | print("\n>>>> The ",fun," offset is ",hex(elf.sym[fun])," (without base)",'\n') 314 | print("\n>>>> The ",fun," offset is ",hex(addr)," (with base)",'\n') 315 | return addr 316 | 317 | def got(fun,*pie_base) : 318 | ''' 319 | ------ 320 | Descriptions 321 | Binary file function got address offset 322 | 二进制文件函数got表地址偏移 323 | 324 | ------ 325 | Parameters 326 | fun : function name 327 | pie_base (optional) : the binary base when pie enabled 328 | 329 | ------ 330 | Returns 331 | got addr of func 332 | ''' 333 | global elfbase 334 | if elfbase != 0: 335 | pie_base = elfbase 336 | if(len(pie_base)<=0): 337 | addr = elf.got[fun] 338 | print("\n>>>> The ",fun," got is ",hex(addr),'\n') 339 | return addr 340 | else : 341 | addr = elf.got[fun]+pie_base 342 | print("\n>>>> pie_base ",pie_base,'\n') 343 | print("\n>>>> The ",fun," offset is ",hex(elf.got[fun])," (without base)",'\n') 344 | print("\n>>>> The ",fun," got is ",hex(addr)," (with base)",'\n') 345 | return addr 346 | 347 | def plt(fun,*pie_base) : 348 | ''' 349 | ------ 350 | Descriptions 351 | Binary file function plt address offset 352 | 二进制文件函数plt表地址偏移 353 | 354 | ------ 355 | Parameters 356 | fun : function name 357 | pie_base (optional) : the binary base when pie enabled 358 | 359 | ------ 360 | Returns 361 | plt addr of func 362 | ''' 363 | global elfbase 364 | if elfbase != 0: 365 | pie_base = elfbase 366 | if(len(pie_base)<=0): 367 | addr = elf.plt[fun] 368 | print("\n>>>> The ",fun," plt is ",hex(addr),'\n') 369 | return addr 370 | else : 371 | addr = elf.plt[fun]+pie_base 372 | print("\n>>>> pie_base ",pie_base,'\n') 373 | print("\n>>>> The ",fun," offset is ",hex(elf.plt[fun])," (without base)",'\n') 374 | print("\n>>>> The ",fun," plt is ",hex(addr)," (with base)",'\n') 375 | return addr 376 | 377 | def libcsym(fun,off=0): 378 | ''' 379 | ------ 380 | Descriptions 381 | libc function address offset 382 | libc文件函数地址偏移 383 | 用于计算一两个libc函数地址时比较方便 384 | 385 | ------ 386 | Parameters 387 | fun : function name 388 | off (optional) : the libc base when pie enabled 389 | 390 | ------ 391 | Returns 392 | addr of libc func 393 | ''' 394 | global libcbase 395 | if libcbase != 0: 396 | off = libcbase 397 | if(off==0): 398 | addr = libc.sym[fun] 399 | print("\n>>>> The ",fun," offset is ",hex(addr),'\n') 400 | return addr 401 | else: 402 | addr = libc.sym[fun]+off 403 | print("\n>>>> The ",fun," offset is ",hex(libc.sym[fun]),' (without base)\n') 404 | print("\n>>>> The ",fun," offset is ",hex(addr),' (with base)\n') 405 | return addr 406 | 407 | def setbase(add): 408 | ''' 409 | ------ 410 | Descriptions 411 | Add the base address and offset to get the real address 412 | 给二进制文件设置基址 413 | 414 | ------ 415 | Parameters 416 | add : the base addr of binary 417 | 418 | ------ 419 | Returns 420 | None 421 | ''' 422 | global elfbase 423 | elfbase = add 424 | print("\n>>>> your binary base is ",hex(elfbase)) 425 | 426 | def setlibcbase(add): 427 | ''' 428 | ------ 429 | Descriptions 430 | Add the base address and offset to get the real address 431 | 给libc设置基址 432 | 433 | ------ 434 | Parameters 435 | add : the base addr of binary 436 | 437 | ------ 438 | Returns 439 | None 440 | ''' 441 | global libcbase 442 | libcbase = add 443 | print("\n>>>> your libc base is ",hex(libcbase)) 444 | 445 | def elsym(add): 446 | ''' 447 | ------ 448 | Descriptions 449 | set elfbase for binary 450 | 基址和偏移相加得到真实地址 451 | 452 | ------ 453 | Parameters 454 | add : the addr needed to be added 455 | 456 | ------ 457 | Returns 458 | elfbase + add 459 | ''' 460 | elfbase = globals()['elfbase'] 461 | print("\n>>>> The elf add with base is ",hex(elfbase+add)) 462 | return elfbase+add 463 | 464 | def lisym(add): 465 | ''' 466 | ------ 467 | Descriptions 468 | set elfbase for binary 469 | 基址和偏移相加得到真实地址 470 | 471 | ------ 472 | Parameters 473 | add : the addr needed to be added 474 | 475 | ------ 476 | Returns 477 | libcbase + add 478 | ''' 479 | libcbase = globals()['libcbase'] 480 | print("\n>>>> The libc add with base is ",hex(libcbase+add)) 481 | return libcbase+add 482 | 483 | def searchlibc(fun,real_addr,mode=1,offset=0) : 484 | ''' 485 | ------ 486 | Descriptions 487 | Determine the libc version from the leaked function real address and return /bin/sh string address and system function address 488 | 由泄露的函数真实地址确定libc版本,并返回/bin/sh字符串地址和system函数地址 489 | 490 | ------ 491 | Parameters 492 | fun : function name 493 | real_addr =: leaked real addr of func 494 | mode : flag of using libc (1) or libcsearcher (0) 495 | offset : the offset between leaked addr and base addr of func 496 | 497 | ------ 498 | Returns 499 | binsh, system 500 | ''' 501 | 502 | if mode : 503 | libc = globals()['libc'] 504 | base_addr = real_addr - libc.symbols[fun] - offset 505 | setlibcbase(base_addr) 506 | system = libc.symbols['system'] + base_addr 507 | binsh = libc.search(b'/bin/sh').__next__() + base_addr 508 | print("\n>>>> The base addr is ",hex(base_addr),'\n') 509 | print("\n>>>> The bin_addr ",hex(binsh),'\n') 510 | print("\n>>>> The system addr is ",hex(system),'\n') 511 | return binsh, system 512 | else : 513 | libc=LibcSearcher(fun,real_addr-offset) 514 | offset=real_addr-libc.dump(fun) 515 | setlibcbase(offset) 516 | binsh=offset+libc.dump('str_bin_sh') 517 | system=offset+libc.dump('system') 518 | print("\n>>>> The offset is ",hex(offset),'\n') 519 | print("\n>>>> The bin_addr ",hex(binsh),'\n') 520 | print("\n>>>> The system addr is ",hex(system),'\n') 521 | return binsh, system 522 | 523 | def csu(csu_end_addr=0,csu_front_addr=0, r12=0,r13=0, r14=0, r15=0,rbx=0, rbp=1, last=None): 524 | ''' 525 | ------ 526 | Descriptions 527 | ret2csu utilizes rop chain 528 | ret2csu利用rop链 529 | # pop rbx,rbp,r12,r13,r14,r15 530 | # rbx should be 0, 531 | # rbp should be 1,enable not to jump 532 | # r15 should be the function we want to call 533 | # rdi=edi=r12d 534 | # rsi=r13 535 | # rdx=r14 536 | 537 | ------ 538 | Parameters 539 | rbx, rbp, r12, r13, r14, r15 : registers 540 | csu_end_addr,csu_front_addr, last : gadgets 541 | 542 | ------ 543 | Returns 544 | payload 545 | ''' 546 | # pop rbx,rbp,r12,r13,r14,r15 547 | # rbx should be 0, 548 | # rbp should be 1,enable not to jump 549 | # r15 should be the function we want to call 550 | # rdi=edi=r12d 551 | # rsi=r13 552 | # rdx=r14 553 | payload = p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) 554 | payload += p64(csu_front_addr) 555 | return payload 556 | 557 | """ 558 | mov rdx, r14 559 | mov rsi, r13 560 | mov edi, r12d 561 | call ds:(__frame_dummy_init_array_entry - 403E00h)[r15+rbx*8] 562 | add rbx, 1 563 | cmp rbp, rbx 564 | jnz short loc_401330 565 | 566 | loc_401346: 567 | add rsp, 8 568 | pop rbx 569 | pop rbp 570 | pop r12 571 | pop r13 572 | pop r14 573 | pop r15 574 | retn 575 | 576 | """ 577 | 578 | def fmt(offset,begin,end,size,written): 579 | ''' 580 | ------ 581 | Descriptions 582 | fmt attack 583 | fmt攻击 584 | 585 | ------ 586 | Parameters 587 | offset : fmt 偏移 588 | begin : 将要被写入的地址 589 | end : 将要写入的地址 590 | size : 写入的格式化字符串形式 591 | wriiten : printf函数已写入的字节数 592 | 593 | ------ 594 | Returns 595 | payload 596 | 597 | elfbase + add 598 | # offset(int) - 您控制的第一个格式化程序的偏移量 599 | # 字典(dict) - 被写入地址对应->写入的数据,可多个对应{addr: value, addr2: value2} 600 | # numbwritten(int) - printf函数已写入的字节数 601 | # write_size(str) - 必须是byte,short或int。告诉您是否要逐字节写入,短按short或int(hhn,hn或n) 602 | ''' 603 | payload = fmtstr_payload(offset,{begin: end},write_size = size,numbwritten=written) 604 | return payload 605 | 606 | def ROPgadget(bin, order=None, gr = '' ,option=''): 607 | ''' 608 | ------ 609 | Descriptions 610 | find gadgets you want using ROPgadget 611 | 使用ROPgadget找到想要的gadget 612 | 613 | ------ 614 | Parameters 615 | bin : binary file 616 | order : gadget you want 617 | gr : using grep (1) or not (0) 618 | option : to find a string 619 | 620 | ------ 621 | Returns 622 | elfbase + add 623 | ''' 624 | if option == 'string': 625 | cmd = f'ROPgadget --binary {bin} --string "{order}"' 626 | else: 627 | if gr =='': 628 | cmd = f'ROPgadget --binary {bin} --only "pop|ret"' 629 | else: 630 | cmd = f'ROPgadget --binary {bin} --only "pop|ret" | grep {gr}' 631 | # os.system(cmd) 632 | result = os.popen(cmd).read() 633 | if option == "show": 634 | print(result) 635 | return None 636 | addresses = result.split('\n') 637 | gadget = None 638 | for address in addresses: 639 | if order == None: 640 | return None 641 | if order in address: 642 | if order.strip() in address.split(':')[1].strip(): 643 | gadget = address.split(':')[0].strip() 644 | break 645 | if gadget: 646 | print(f">>> '{order}' address:", gadget) 647 | else: 648 | print(f">>> '{order}' address not found.") 649 | return None 650 | 651 | return int(gadget,16) 652 | 653 | 654 | #----------------------------------------------------------------------------------------- 655 | # Alias 656 | #----------------------------------------------------------------------------------------- 657 | 658 | 659 | # sendafter(delim,data) 660 | sda = lambda delim,data :p.sendafter(delim,data) 661 | # send(data) 662 | sd = lambda data :p.send(data) 663 | # sendline(data) 664 | sl = lambda data :p.sendline(data) 665 | # sendlineafter(delim,data) 666 | sla = lambda delim,data :p.sendlineafter(delim,data) 667 | # recv() 668 | rc = lambda data=None: p.recv() if data is None else p.recv(data) 669 | # recvuntil(delims,drop) 670 | ru = lambda delims,drop=True :p.recvuntil(delims,drop) 671 | # int(data,16) 672 | int16 = lambda data :int(data,16) 673 | # u32(data.ljust(4,b'\x00')) 674 | uu32 = lambda data :u32(data.ljust(4,b'\x00')) 675 | # u64(data.ljust(8,b'\x00')) 676 | uu64 = lambda data :u64(data.ljust(8,b'\x00')) 677 | # log.success(name+'='+hex(addr)) 678 | lg = lambda name,addr :log.success(name+'='+hex(addr)) 679 | # interactive() 680 | ia = lambda :p.interactive() 681 | # close() 682 | cl = lambda :p.close() 683 | # getflag 684 | gf = lambda :p.sendline('cat flag') -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | This module provides functionality for ctf pwn. 4 | Including some common operations in learning and competitions 5 | 6 | Welcome all masters to provide advice on the code 7 | Please visit https://lmarch2.top/posts/8c945bd4/ for code details 8 | 9 | -------------------------------------- 10 | Excalibur -- Sword of Contract Victory 11 | -------------------------------------- 12 | 13 | Example: 14 | >>> from Excalibur2 import* 15 | """ 16 | 17 | 18 | # Excalibur 19 | 20 | 21 | #----------------------------------------------------------------------------------------- 22 | # Packages 23 | #----------------------------------------------------------------------------------------- 24 | 25 | 26 | from pwn import * 27 | import os 28 | from struct import pack 29 | from ctypes import * 30 | import base64 31 | import click 32 | from LibcSearcher import * 33 | 34 | 35 | #----------------------------------------------------------------------------------------- 36 | # Settings 37 | #----------------------------------------------------------------------------------------- 38 | 39 | elfbase = 0 40 | libcbase = 0 41 | 42 | 43 | def default(mode): 44 | if mode == 'm': 45 | setterminal("tmux","new-window") 46 | setcontext() 47 | elif mode == 'h': 48 | setterminal("tmux","splitw","-h") 49 | setcontext() 50 | 51 | 52 | # Set up debugging terminal (especially efficient on WSL2) 53 | # 如何在WSL2上使用tmux调试请看https://lmarch2.top/posts/19b7c9d1/ 54 | def setterminal(termin='tmux',*args): 55 | ''' 56 | ------ 57 | Descriptions 58 | set debug terminal 59 | 设置调试终端 60 | 61 | ------ 62 | Parameters 63 | termin : debug terminal (default tmux) 64 | args (optional) : context.terminal = [termin,args] 65 | 66 | ------ 67 | Returns 68 | None 69 | ''' 70 | if(len(args)<=0): 71 | context.terminal = [termin, 'splitw', '-h'] 72 | else: 73 | context.terminal = [termin,*args] 74 | 75 | def setcontext(ar = 64, de = 1): 76 | ''' 77 | ------ 78 | Descriptions 79 | set your structure and debug mode 80 | 设置文件架构和调试模式 81 | 82 | ------ 83 | Parameters 84 | ar : choose arch for amd64 (64) or i386 (32) 85 | de : using debug mode (1) or not (0) 86 | 87 | ------ 88 | Returns 89 | None 90 | ''' 91 | if ar == 32: 92 | if de == 0: 93 | context(os='linux', arch='i386') 94 | else: 95 | context(log_level='debug', os='linux', arch='i386') 96 | else: 97 | if de == 0: 98 | context(os='linux', arch='amd64') 99 | else: 100 | context(os='linux', arch='amd64', log_level='debug') 101 | 102 | def debug(c = 0): 103 | ''' 104 | ------ 105 | Descriptions 106 | debug 107 | To use gdb debugging, please use the command line parameter G, such as: python3 exp.py G 108 | 调试 109 | 若要使用gdb调试,请使用命令行参数G,如:python3 exp.py G 110 | 111 | ------ 112 | Parameters 113 | c : gdb attach上进程之后执行的命令字符串 (0) 114 | 115 | ------ 116 | Returns 117 | None 118 | ''' 119 | if args.G: 120 | if(c): 121 | gdb.attach(p, c) 122 | else: 123 | gdb.attach(p) 124 | #pause() 125 | 126 | def prb(data): 127 | ''' 128 | ------ 129 | Descriptions 130 | print raw bytes without escaping 131 | 不转义打印原始字符串 132 | 133 | ------ 134 | Parameters 135 | data : the data you want to print 136 | 137 | ------ 138 | Returns 139 | None 140 | ''' 141 | for byte in data: 142 | print(f"\\x{byte:02x}", end="") 143 | print() 144 | 145 | def pr(addr) : 146 | '''print abbreviation 147 | 打印''' 148 | print(addr) 149 | 150 | def prh(addr) : 151 | '''print Hexadecimal data abbreviation 152 | 打印十六进制''' 153 | print(hex(addr)) 154 | 155 | def prl(addr) : 156 | '''print length of data abbreviation 157 | 打印数据长度''' 158 | print(len(addr)) 159 | 160 | def prhl(addr) : 161 | '''print length of data abbreviation 162 | 打印数据长度''' 163 | print(hex(len(addr))) 164 | 165 | def lib(arg = '/usr/lib/x86_64-linux-gnu/libc.so.6') : 166 | ''' 167 | ------ 168 | Descriptions 169 | load libc, default local system libc 170 | 加载libc,默认本地系统libc 171 | 172 | ------ 173 | Parameters 174 | arg : the path of libc 175 | 176 | ------ 177 | Returns 178 | None 179 | ''' 180 | global libc 181 | libc = ELF(arg) 182 | def el(arg='pwn') : 183 | ''' 184 | ------ 185 | Descriptions 186 | load elf, default filename pwn 187 | 加载elf,默认文件名是pwn 188 | 189 | ------ 190 | Parameters 191 | arg : the path of elf 192 | 193 | ------ 194 | Returns 195 | None 196 | ''' 197 | global elf 198 | elf = ELF(arg) 199 | def proc(bin="./pwn") : 200 | ''' 201 | ------ 202 | Descriptions 203 | load binary when no command line parameter R provided 204 | 没有命令行参数R时加载二进制文件 205 | 206 | ------ 207 | Parameters 208 | bin : the path of binary 209 | 210 | ------ 211 | Returns 212 | p 213 | ''' 214 | if not args.R: 215 | global p 216 | p = process(bin) 217 | return p 218 | 219 | def remo(ip,port='') : 220 | ''' 221 | ------ 222 | Descriptions 223 | connect to remote when command line parameter R provided 224 | 有命令行参数R时连接到远程 225 | 226 | ------ 227 | Parameters 228 | ip : ip of remote 229 | port: port of remote 230 | using remo(ip) when given ip = ip:port or ip = ip port 231 | using remo(ip,port) when given ip and port 232 | 233 | ------ 234 | Returns 235 | p 236 | ''' 237 | if args.R: 238 | global p 239 | if ' ' in ip : 240 | ip_port = ip.split(' ') 241 | p = remote(ip_port[0],ip_port[1]) 242 | elif not ':' in ip : 243 | p = remote(ip,port) 244 | else: 245 | ip_port = ip.split(':') 246 | p = remote(ip_port[0],ip_port[1]) 247 | return p 248 | 249 | def get_addr64() : 250 | ''' 251 | ------ 252 | Descriptions 253 | Receive leaked 64-bit libc address 254 | 接收泄露的64位libc地址 255 | 256 | ------ 257 | Parameters 258 | None 259 | 260 | ------ 261 | Returns 262 | recieved addr 263 | ''' 264 | recvaddr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) 265 | print("\n>>>> The leaked addr is ",hex(recvaddr),'\n') 266 | return recvaddr 267 | 268 | def get_addr32() : 269 | ''' 270 | ------ 271 | Descriptions 272 | Receive leaked 32-bit libc address 273 | 接收泄露的32位libc地址 274 | 275 | ------ 276 | Parameters 277 | None 278 | 279 | ------ 280 | Returns 281 | recieved addr 282 | ''' 283 | recvaddr = u32(p.recvuntil(b'\xf7')[-4:]) 284 | print("\n>>>> The leaked addr is ",hex(recvaddr),'\n') 285 | return recvaddr 286 | 287 | def sym(fun,*pie_base) : 288 | ''' 289 | ------ 290 | Descriptions 291 | Binary file function address offset 292 | 二进制文件函数地址偏移 293 | 294 | ------ 295 | Parameters 296 | fun : function name 297 | pie_base (optional) : the binary base when pie enabled 298 | 299 | ------ 300 | Returns 301 | addr of func 302 | ''' 303 | global elfbase 304 | if elfbase != 0: 305 | pie_base = elfbase 306 | if(len(pie_base)<=0): 307 | addr = elf.sym[fun] 308 | print("\n>>>> The ",fun," offset is ",hex(addr),'\n') 309 | return addr 310 | else : 311 | addr = elf.sym[fun]+pie_base 312 | print("\n>>>> pie_base ",pie_base,'\n') 313 | print("\n>>>> The ",fun," offset is ",hex(elf.sym[fun])," (without base)",'\n') 314 | print("\n>>>> The ",fun," offset is ",hex(addr)," (with base)",'\n') 315 | return addr 316 | 317 | def got(fun,*pie_base) : 318 | ''' 319 | ------ 320 | Descriptions 321 | Binary file function got address offset 322 | 二进制文件函数got表地址偏移 323 | 324 | ------ 325 | Parameters 326 | fun : function name 327 | pie_base (optional) : the binary base when pie enabled 328 | 329 | ------ 330 | Returns 331 | got addr of func 332 | ''' 333 | global elfbase 334 | if elfbase != 0: 335 | pie_base = elfbase 336 | if(len(pie_base)<=0): 337 | addr = elf.got[fun] 338 | print("\n>>>> The ",fun," got is ",hex(addr),'\n') 339 | return addr 340 | else : 341 | addr = elf.got[fun]+pie_base 342 | print("\n>>>> pie_base ",pie_base,'\n') 343 | print("\n>>>> The ",fun," offset is ",hex(elf.got[fun])," (without base)",'\n') 344 | print("\n>>>> The ",fun," got is ",hex(addr)," (with base)",'\n') 345 | return addr 346 | 347 | def plt(fun,*pie_base) : 348 | ''' 349 | ------ 350 | Descriptions 351 | Binary file function plt address offset 352 | 二进制文件函数plt表地址偏移 353 | 354 | ------ 355 | Parameters 356 | fun : function name 357 | pie_base (optional) : the binary base when pie enabled 358 | 359 | ------ 360 | Returns 361 | plt addr of func 362 | ''' 363 | global elfbase 364 | if elfbase != 0: 365 | pie_base = elfbase 366 | if(len(pie_base)<=0): 367 | addr = elf.plt[fun] 368 | print("\n>>>> The ",fun," plt is ",hex(addr),'\n') 369 | return addr 370 | else : 371 | addr = elf.plt[fun]+pie_base 372 | print("\n>>>> pie_base ",pie_base,'\n') 373 | print("\n>>>> The ",fun," offset is ",hex(elf.plt[fun])," (without base)",'\n') 374 | print("\n>>>> The ",fun," plt is ",hex(addr)," (with base)",'\n') 375 | return addr 376 | 377 | def libcsym(fun,off=0): 378 | ''' 379 | ------ 380 | Descriptions 381 | libc function address offset 382 | libc文件函数地址偏移 383 | 用于计算一两个libc函数地址时比较方便 384 | 385 | ------ 386 | Parameters 387 | fun : function name 388 | off (optional) : the libc base when pie enabled 389 | 390 | ------ 391 | Returns 392 | addr of libc func 393 | ''' 394 | global libcbase 395 | if libcbase != 0: 396 | off = libcbase 397 | if(off==0): 398 | addr = libc.sym[fun] 399 | print("\n>>>> The ",fun," offset is ",hex(addr),'\n') 400 | return addr 401 | else: 402 | addr = libc.sym[fun]+off 403 | print("\n>>>> The ",fun," offset is ",hex(libc.sym[fun]),' (without base)\n') 404 | print("\n>>>> The ",fun," offset is ",hex(addr),' (with base)\n') 405 | return addr 406 | 407 | def setbase(add): 408 | ''' 409 | ------ 410 | Descriptions 411 | Add the base address and offset to get the real address 412 | 给二进制文件设置基址 413 | 414 | ------ 415 | Parameters 416 | add : the base addr of binary 417 | 418 | ------ 419 | Returns 420 | None 421 | ''' 422 | global elfbase 423 | elfbase = add 424 | print("\n>>>> your binary base is ",hex(elfbase)) 425 | 426 | def setlibcbase(add): 427 | ''' 428 | ------ 429 | Descriptions 430 | Add the base address and offset to get the real address 431 | 给libc设置基址 432 | 433 | ------ 434 | Parameters 435 | add : the base addr of binary 436 | 437 | ------ 438 | Returns 439 | None 440 | ''' 441 | global libcbase 442 | libcbase = add 443 | print("\n>>>> your libc base is ",hex(libcbase)) 444 | 445 | def elsym(add): 446 | ''' 447 | ------ 448 | Descriptions 449 | set elfbase for binary 450 | 基址和偏移相加得到真实地址 451 | 452 | ------ 453 | Parameters 454 | add : the addr needed to be added 455 | 456 | ------ 457 | Returns 458 | elfbase + add 459 | ''' 460 | elfbase = globals()['elfbase'] 461 | print("\n>>>> The elf add with base is ",hex(elfbase+add)) 462 | return elfbase+add 463 | 464 | def lisym(add): 465 | ''' 466 | ------ 467 | Descriptions 468 | set elfbase for binary 469 | 基址和偏移相加得到真实地址 470 | 471 | ------ 472 | Parameters 473 | add : the addr needed to be added 474 | 475 | ------ 476 | Returns 477 | libcbase + add 478 | ''' 479 | libcbase = globals()['libcbase'] 480 | print("\n>>>> The libc add with base is ",hex(libcbase+add)) 481 | return libcbase+add 482 | 483 | def searchlibc(fun,real_addr,mode=1,offset=0) : 484 | ''' 485 | ------ 486 | Descriptions 487 | Determine the libc version from the leaked function real address and return /bin/sh string address and system function address 488 | 由泄露的函数真实地址确定libc版本,并返回/bin/sh字符串地址和system函数地址 489 | 490 | ------ 491 | Parameters 492 | fun : function name 493 | real_addr =: leaked real addr of func 494 | mode : flag of using libc (1) or libcsearcher (0) 495 | offset : the offset between leaked addr and base addr of func 496 | 497 | ------ 498 | Returns 499 | binsh, system 500 | ''' 501 | 502 | if mode : 503 | libc = globals()['libc'] 504 | base_addr = real_addr - libc.symbols[fun] - offset 505 | setlibcbase(base_addr) 506 | system = libc.symbols['system'] + base_addr 507 | binsh = libc.search(b'/bin/sh').__next__() + base_addr 508 | print("\n>>>> The base addr is ",hex(base_addr),'\n') 509 | print("\n>>>> The bin_addr ",hex(binsh),'\n') 510 | print("\n>>>> The system addr is ",hex(system),'\n') 511 | return binsh, system 512 | else : 513 | libc=LibcSearcher(fun,real_addr-offset) 514 | offset=real_addr-libc.dump(fun) 515 | setlibcbase(offset) 516 | binsh=offset+libc.dump('str_bin_sh') 517 | system=offset+libc.dump('system') 518 | print("\n>>>> The offset is ",hex(offset),'\n') 519 | print("\n>>>> The bin_addr ",hex(binsh),'\n') 520 | print("\n>>>> The system addr is ",hex(system),'\n') 521 | return binsh, system 522 | 523 | def csu(csu_end_addr=0,csu_front_addr=0, r12=0,r13=0, r14=0, r15=0,rbx=0, rbp=1, last=None): 524 | ''' 525 | ------ 526 | Descriptions 527 | ret2csu utilizes rop chain 528 | ret2csu利用rop链 529 | # pop rbx,rbp,r12,r13,r14,r15 530 | # rbx should be 0, 531 | # rbp should be 1,enable not to jump 532 | # r15 should be the function we want to call 533 | # rdi=edi=r12d 534 | # rsi=r13 535 | # rdx=r14 536 | 537 | ------ 538 | Parameters 539 | rbx, rbp, r12, r13, r14, r15 : registers 540 | csu_end_addr,csu_front_addr, last : gadgets 541 | 542 | ------ 543 | Returns 544 | payload 545 | ''' 546 | # pop rbx,rbp,r12,r13,r14,r15 547 | # rbx should be 0, 548 | # rbp should be 1,enable not to jump 549 | # r15 should be the function we want to call 550 | # rdi=edi=r12d 551 | # rsi=r13 552 | # rdx=r14 553 | payload = p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) 554 | payload += p64(csu_front_addr) 555 | return payload 556 | 557 | """ 558 | mov rdx, r14 559 | mov rsi, r13 560 | mov edi, r12d 561 | call ds:(__frame_dummy_init_array_entry - 403E00h)[r15+rbx*8] 562 | add rbx, 1 563 | cmp rbp, rbx 564 | jnz short loc_401330 565 | 566 | loc_401346: 567 | add rsp, 8 568 | pop rbx 569 | pop rbp 570 | pop r12 571 | pop r13 572 | pop r14 573 | pop r15 574 | retn 575 | 576 | """ 577 | 578 | def fmt(offset,begin,end,size,written): 579 | ''' 580 | ------ 581 | Descriptions 582 | fmt attack 583 | fmt攻击 584 | 585 | ------ 586 | Parameters 587 | offset : fmt 偏移 588 | begin : 将要被写入的地址 589 | end : 将要写入的地址 590 | size : 写入的格式化字符串形式 591 | wriiten : printf函数已写入的字节数 592 | 593 | ------ 594 | Returns 595 | payload 596 | 597 | elfbase + add 598 | # offset(int) - 您控制的第一个格式化程序的偏移量 599 | # 字典(dict) - 被写入地址对应->写入的数据,可多个对应{addr: value, addr2: value2} 600 | # numbwritten(int) - printf函数已写入的字节数 601 | # write_size(str) - 必须是byte,short或int。告诉您是否要逐字节写入,短按short或int(hhn,hn或n) 602 | ''' 603 | payload = fmtstr_payload(offset,{begin: end},write_size = size,numbwritten=written) 604 | return payload 605 | 606 | def ROPgadget(bin, order=None, gr = '' ,option=''): 607 | ''' 608 | ------ 609 | Descriptions 610 | find gadgets you want using ROPgadget 611 | 使用ROPgadget找到想要的gadget 612 | 613 | ------ 614 | Parameters 615 | bin : binary file 616 | order : gadget you want 617 | gr : using grep (1) or not (0) 618 | option : to find a string 619 | 620 | ------ 621 | Returns 622 | gadget 623 | ''' 624 | if option == 'string': 625 | cmd = f'ROPgadget --binary {bin} --string "{order}"' 626 | else: 627 | if gr =='': 628 | cmd = f'ROPgadget --binary {bin} --only "pop|ret"' 629 | else: 630 | cmd = f'ROPgadget --binary {bin} --only "pop|ret" | grep {gr}' 631 | # os.system(cmd) 632 | result = os.popen(cmd).read() 633 | if option == "show": 634 | print(result) 635 | return None 636 | addresses = result.split('\n') 637 | gadget = None 638 | for address in addresses: 639 | if order == None: 640 | return None 641 | if order in address: 642 | if order.strip() in address.split(':')[1].strip(): 643 | gadget = address.split(':')[0].strip() 644 | break 645 | if gadget: 646 | print(f">>> '{order}' address:", gadget) 647 | else: 648 | print(f">>> '{order}' address not found.") 649 | return None 650 | 651 | return int(gadget,16) 652 | 653 | 654 | #----------------------------------------------------------------------------------------- 655 | # Alias 656 | #----------------------------------------------------------------------------------------- 657 | 658 | 659 | # sendafter(delim,data) 660 | sda = lambda delim,data :p.sendafter(delim,data) 661 | # send(data) 662 | sd = lambda data :p.send(data) 663 | # sendline(data) 664 | sl = lambda data :p.sendline(data) 665 | # sendlineafter(delim,data) 666 | sla = lambda delim,data :p.sendlineafter(delim,data) 667 | # recv() 668 | rc = lambda data=None: p.recv() if data is None else p.recv(data) 669 | # recvuntil(delims,drop) 670 | ru = lambda delims,drop=True :p.recvuntil(delims,drop) 671 | # int(data,16) 672 | int16 = lambda data :int(data,16) 673 | # u32(data.ljust(4,b'\x00')) 674 | uu32 = lambda data :u32(data.ljust(4,b'\x00')) 675 | # u64(data.ljust(8,b'\x00')) 676 | uu64 = lambda data :u64(data.ljust(8,b'\x00')) 677 | # log.success(name+'='+hex(addr)) 678 | lg = lambda name,addr :log.success(name+'='+hex(addr)) 679 | # interactive() 680 | ia = lambda :p.interactive() 681 | # close() 682 | cl = lambda :p.close() 683 | # getflag 684 | gf = lambda :p.sendline('cat flag') --------------------------------------------------------------------------------