├── .gitignore ├── Libc.py ├── Makefile ├── patch_elf.py ├── pwninit.py └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .vscode 3 | .gitignore -------------------------------------------------------------------------------- /Libc.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import shutil 4 | import argparse 5 | import re 6 | import subprocess 7 | import wget 8 | from pyunpack import Archive 9 | from pwn import ELF 10 | import uuid 11 | import patoolib 12 | 13 | pkd_url = "https://launchpad.net/ubuntu/+archive/primary/+files" 14 | 15 | 16 | def libcVersion(path) -> tuple: 17 | f = open(path, "rb") 18 | _ = f.read() 19 | f.close() 20 | pattern = b"GLIBC (\d+\.\d+)-(\w+\d+(?:\.\d+)?)?" 21 | res = re.search(pattern, _) 22 | if res: 23 | libcVersion = res.group(1).decode() 24 | releaseNumber = res.group(2).decode() 25 | return (libcVersion, releaseNumber) 26 | else: 27 | return "" 28 | 29 | 30 | def extract(archive: str, extractPath: str, extractFiles: tuple = ()): 31 | try: 32 | Archive(archive).extractall(extractPath) 33 | except: 34 | print("err: extract()") 35 | exit(1) 36 | 37 | 38 | class LIBC(ELF): 39 | # Ex: GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) 40 | # "2.27" is libcVersion 41 | # "3ubuntu1" is releaseNumber 42 | def __init__(self, path): 43 | super().__init__(path, checksec=0) 44 | self.libcVersion, self.releaseNumber = libcVersion(path) 45 | if (self.libcVersion == ""): 46 | print("Ubuntu glibc not detected!") 47 | exit(1) 48 | self.libc6_bin_deb = "libc6_{}-{}_{}.deb".format( 49 | self.libcVersion, self.releaseNumber, self.arch) 50 | self.libc6_dbg_deb = "libc6-dbg_{}-{}_{}.deb".format( 51 | self.libcVersion, self.releaseNumber, self.arch) 52 | self.workDir = "/tmp/pwninit_{}".format(str(uuid.uuid4())) 53 | self.dbgSym = "{}/dbgsym".format(self.workDir) 54 | self.libcBin = "{}/libcbin".format(self.workDir) 55 | if os.path.exists(self.workDir): 56 | shutil.rmtree(self.workDir) 57 | os.mkdir(self.workDir) 58 | 59 | def __del__(self): 60 | if os.path.exists(self.workDir): 61 | shutil.rmtree(self.workDir) 62 | 63 | def getLinker(self, path=".") -> ELF: 64 | # get ld binary 65 | _ = "{}/{}".format(pkd_url, self.libc6_bin_deb) 66 | archive = "{}/{}".format(self.workDir, self.libc6_bin_deb) 67 | wget.download( 68 | _, 69 | archive) 70 | _ = self.libcBin 71 | 72 | if not os.path.exists(_): 73 | os.mkdir(_) 74 | extract(archive, _) 75 | 76 | try: 77 | 78 | linkerPath = "{}/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2".format( 79 | _) 80 | 81 | if not os.path.exists(linkerPath): 82 | linkerPath = "{}/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2".format( 83 | _) 84 | 85 | if not os.path.exists(linkerPath): 86 | raise FileNotFoundError 87 | 88 | ELF(linkerPath, checksec=False) 89 | shutil.copy(linkerPath, path) 90 | linker = ELF("{}/ld-linux-x86-64.so.2".format(path), 91 | checksec=False) 92 | 93 | except FileNotFoundError: 94 | print("err: Can't find the linkerfile") 95 | exit(1) 96 | 97 | _ = "{}/{}".format(pkd_url, self.libc6_dbg_deb) 98 | archive = "{}/{}".format(self.workDir, self.libc6_dbg_deb) 99 | if not os.path.exists(archive): 100 | wget.download( 101 | _, 102 | archive) 103 | 104 | _ = self.dbgSym 105 | if not os.path.exists(_): 106 | os.mkdir(_) 107 | extract(archive, _) 108 | # try unstrip the linkerfile 109 | try: 110 | _ = subprocess.check_call( 111 | [ 112 | "/usr/bin/eu-unstrip", 113 | "-o", linker.path, 114 | linker.path, 115 | "{}/usr/lib/debug/lib/{}-linux-gnu/ld-{}.so".format( 116 | self.dbgSym, 117 | "x86_64" if self.arch == "amd64" else "i386", 118 | self.libcVersion 119 | ) 120 | ], 121 | stderr=open("/tmp/pwninit_log", "a+") 122 | ) 123 | except subprocess.CalledProcessError: 124 | _ = subprocess.check_call( 125 | [ 126 | "/usr/bin/eu-unstrip", 127 | "-o", linker.path, 128 | linker.path, 129 | "{}/usr/lib/debug/.build-id/{}/{}.debug".format( 130 | self.dbgSym, 131 | linker.buildid[:1].hex(), 132 | linker.buildid[1:].hex() 133 | ) 134 | ], 135 | stderr=open("/tmp/pwninit_log", "a+") 136 | ) 137 | if _: 138 | print("err {}: eu-unstrip".format(_)) 139 | exit(1) 140 | return linker 141 | 142 | def unstripLibc(self): 143 | archive = "{}/{}".format(self.workDir, self.libc6_dbg_deb) 144 | linkArchive = "{}/{}".format(pkd_url, self.libc6_dbg_deb) 145 | if not os.path.exists(archive): 146 | wget.download( 147 | linkArchive, 148 | archive) 149 | 150 | _ = self.dbgSym 151 | if not os.path.exists(_): 152 | os.mkdir(_) 153 | extract(archive, _) 154 | 155 | try: 156 | _ = subprocess.check_call( 157 | [ 158 | "/usr/bin/eu-unstrip", 159 | "-o", self.path, 160 | self.path, 161 | "{}/usr/lib/debug/lib/{}-linux-gnu/libc-{}.so".format( 162 | self.dbgSym, 163 | "x86_64" if self.arch == "amd64" else "i386", 164 | self.libcVersion 165 | ) 166 | ], 167 | stderr=open("/tmp/pwninit_log", "a+") 168 | ) 169 | except subprocess.CalledProcessError: 170 | _ = subprocess.check_call( 171 | [ 172 | "/usr/bin/eu-unstrip", 173 | "-o", self.path, 174 | self.path, 175 | "{}/usr/lib/debug/.build-id/{}/{}.debug".format( 176 | self.dbgSym, 177 | self.buildid[:1].hex(), 178 | self.buildid[1:].hex() 179 | ) 180 | ], 181 | stderr=open("/tmp/pwninit_log", "a+") 182 | ) 183 | if _: 184 | print("err {}: eu-unstrip".format(_)) 185 | exit(1) 186 | 187 | def getSrc(self): 188 | wget.download( 189 | "http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/glibc_{}.orig.tar.xz".format(self.libcVersion)) 190 | 191 | 192 | def main(): 193 | parser = argparse.ArgumentParser() 194 | parser.add_argument("libc", metavar="") 195 | parser.add_argument("-u", "--unstrip", 196 | help="Unstrip the libc file", action="store_true") 197 | parser.add_argument("-ld", "--get_linker", 198 | help="Get the linker for libc", action="store_true") 199 | parser.add_argument("-src", "--get_src", 200 | help="Get soruce code of libc", action="store_true") 201 | args = parser.parse_args() 202 | if not args.libc: 203 | return 1 204 | libcObject = LIBC(args.libc) 205 | if args.unstrip: 206 | libcObject.unstripLibc() 207 | if args.get_linker: 208 | libcObject.getLinker() 209 | if args.get_src: 210 | libcObject.getSrc() 211 | 212 | 213 | if __name__ == '__main__': 214 | main() 215 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | setup: 2 | sudo apt install -y wget patchelf python3 python-is-python3 python3-pip elfutils 3 | sudo pip3 install wget pyunpack pwn patool 4 | -------------------------------------------------------------------------------- /patch_elf.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import subprocess 3 | from pwn import ELF 4 | from Libc import LIBC 5 | 6 | 7 | def patch(bin: ELF, libc: LIBC, ld: ELF): 8 | def get_file_name(file_path): return file_path.split("/")[-1] 9 | if get_file_name(libc.path) != "libc.so.6": 10 | subprocess.check_call( 11 | ["/usr/bin/rm", "-rf", "./libc.so.6"], stderr=open("/tmp/pwninit_log", "a+")) 12 | make_symlink = subprocess.check_call( 13 | ["/bin/ln", "-s", "./{}".format(get_file_name(libc.path)), "libc.so.6"]) 14 | run_patchelf = subprocess.check_call( 15 | ["/usr/bin/patchelf", 16 | "--set-rpath", ".", 17 | "--set-interpreter", "./{}".format(get_file_name(ld.path)), 18 | "--output", "{}_patched".format(get_file_name(bin.path)), 19 | "./{}".format(get_file_name(bin.path)), 20 | ], 21 | stderr=open("/tmp/pwninit_log", "a+") 22 | ) 23 | print("\nNew file: {}_patched".format(get_file_name(bin.path))) 24 | 25 | 26 | def main(): 27 | parser = argparse.ArgumentParser() 28 | parser.add_argument("-b", "--bin", metavar="", 29 | help="", required=True) 30 | parser.add_argument("-l", "--libc", metavar="", 31 | help="", required=True) 32 | parser.add_argument("--ld", help=" (Optional)", 33 | default="/lib64/ld-linux-x86-64.so.2") 34 | args = parser.parse_args() 35 | if (not args.bin) or (not args.libc): 36 | return 1 37 | file_bin = ELF(args.bin) # Check bin is a valid ELF ? 38 | file_libc = LIBC(args.libc) # Check bin is a valid LIBC ? 39 | file_ld = ELF(args.ld, checksec=False) # Check ld is a valid ELF ? 40 | patch(file_bin, file_libc, file_ld) 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /pwninit.py: -------------------------------------------------------------------------------- 1 | import patch_elf 2 | import Libc 3 | import argparse 4 | from pwn import ELF 5 | from contextlib import redirect_stderr 6 | import os 7 | import sys 8 | 9 | 10 | def main(): 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument("-b", "--bin", metavar="", 13 | help="", required=True) 14 | parser.add_argument("-l", "--libc", metavar="", 15 | help="", required=True) 16 | parser.add_argument( 17 | "--ld", help=" (Optional)") 18 | args = parser.parse_args() 19 | if (not args.bin) or (not args.libc): 20 | return 1 21 | file_bin = ELF(args.bin) # Check bin is a valid ELF ? 22 | file_libc = Libc.LIBC(args.libc) # Check bin is a valid LIBC ? 23 | if args.ld: 24 | file_ld = ELF(args.ld, checksec=False) 25 | else: 26 | file_ld = file_libc.getLinker() 27 | file_libc.unstripLibc() 28 | patch_elf.patch(file_bin, file_libc, file_ld) 29 | 30 | 31 | if __name__ == '__main__': 32 | main() 33 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Alt-pwninit 2 | 3 | Auto getting linker, unstripping and getting the source codes of a Ubuntu GLibc 4 | 5 | This script need some dependencies to work properly, Run `make setup` to install the prerequisites. --------------------------------------------------------------------------------