From ab79283359a2ee27c8e0b9d801eab9dd8b6e6fc3 Mon Sep 17 00:00:00 2001 From: Squeasp123 Date: Mon, 6 Oct 2025 20:01:45 +0800 Subject: [PATCH 1/4] create patch error code and exp choosing --- .gitignore | 1 + config.json | 4 +- cpwn.py | 115 +++++++++++++++++++++++++++--------- kernel_exploit/.gdbinit | 0 kernel_exploit/exp.c | 0 requirements.txt | 0 setup.sh | 4 +- template.py | 63 -------------------- template/template.py | 48 +++++++++++++++ template/template_docker.py | 80 +++++++++++++++++++++++++ 10 files changed, 221 insertions(+), 94 deletions(-) create mode 100644 .gitignore mode change 100644 => 100755 config.json mode change 100644 => 100755 kernel_exploit/.gdbinit mode change 100644 => 100755 kernel_exploit/exp.c mode change 100644 => 100755 requirements.txt delete mode 100644 template.py create mode 100755 template/template.py create mode 100644 template/template_docker.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50637b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.git_history \ No newline at end of file diff --git a/config.json b/config.json old mode 100644 new mode 100755 index ba73ae1..e7f4558 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { - "author": "GeekCmore", - "template": "~/.config/cpwn/exp_template.py", + "author": "Squeasp", + "template": "~/.config/cpwn/template/", "script_name": "exp.py", "file_path": "~/.config/cpwn/pkgs", "kernel_file_path": "~/.config/cpwn/kernel_exploit", diff --git a/cpwn.py b/cpwn.py index 40d1561..fbe61ea 100755 --- a/cpwn.py +++ b/cpwn.py @@ -29,15 +29,17 @@ def log_base(msg, color): def log_info(msg): - log_base(msg, "blue") + log_base("[+] " + msg, "blue") +def log_table(msg): + log_base(msg, "blue") def log_success(msg): - log_base(msg, "green") + log_base("[*] " + msg, "green") def log_error(msg): - log_base(msg, "red") + log_base("[-] " + msg, "red") exit(-1) @@ -239,16 +241,19 @@ def detect(target_files: dict = {}) -> dict: return target_files -def get_version_by_libc(file): - result = subprocess.run( - f'strings "{file}" | grep "Ubuntu GLIBC" | tail -n 1', +def get_version_by_libc(file): + result = subprocess.run( # + f'strings "{file}" | grep "Ubuntu GLIBC" | tail -n 1', #在libc文件中查找Ubuntu GLIBC stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, ) - return result.stdout.split("(Ubuntu GLIBC ")[1].split(")")[0] - + try: + version = result.stdout.split("(Ubuntu GLIBC ")[1].split(")")[0] + return version + except: + return 'ERROR' def get_glibc_files(version: str, arch: str) -> dict: """ @@ -305,7 +310,7 @@ def choose_version(): libc_list = sorted(libc_list, key=lambda x: x) for i, row in enumerate(libc_list): table.add_row([str(i), row]) - log_info(table) + log_table(table) idx = int(input("Choose the version you wnat to modify:")) return libc_list[idx] @@ -337,6 +342,8 @@ def do_patch(target_files): version = choose_version() else: version = get_version_by_libc(target_files[BaseFile.LIBC]) + if version == 'ERROR': + return version glibc_files = get_glibc_files(version, arch) if not os.path.exists(glibc_files[BaseFile.LIBC]) or not os.path.exists( glibc_files[BaseFile.LD] @@ -347,7 +354,7 @@ def do_patch(target_files): log_info("Start downloading...") download_give_version_arch(version, arch) else: - log_error("No suitable glibc!") + return 'ERROR' prepared_files[BaseFile.LIBC] = glibc_files[BaseFile.LIBC] prepared_files[BaseFile.LIBC] = glibc_files[BaseFile.LIBC] prepared_files[BaseFile.LD] = glibc_files[BaseFile.LD] @@ -381,21 +388,71 @@ def do_patch(target_files): ) return prepared_files - +def do_error_patch(target_files,template_args): + log_info("patch_failed! No suitable glibc!") + log_info("please patched by yourself! Something useful:") + log_info(f'chmod +x "{target_files[BaseFile.EXECUTABLE]}"') + log_info(f'patchelf --replace-needed libc.so.6 "{target_files[BaseFile.LIBC]}" "{target_files[BaseFile.EXECUTABLE]}"') + log_info(f'patchelf --set-interpreter "{target_files[BaseFile.LD]}" "{target_files[BaseFile.EXECUTABLE]}"') + if prompt(f"Do you want to use the found libc/ld ?"): + target_excutable = target_files[BaseFile.EXECUTABLE] + "_patched" + copy(target_files[BaseFile.EXECUTABLE], target_excutable) + subprocess.run(f'chmod +x "{target_files[BaseFile.EXECUTABLE]}"',text=True, shell=True) + subprocess.run(f'patchelf --replace-needed libc.so.6 "{target_files[BaseFile.LIBC]}" "{target_files[BaseFile.EXECUTABLE]}"',text=True, shell=True) + subprocess.run(f'patchelf --set-interpreter "{target_files[BaseFile.LD]}" "{target_files[BaseFile.EXECUTABLE]}"',text=True, shell=True) + template_args["libc_path"] = {target_files[BaseFile.LIBC]} + template_args["src_path"] = 'error' + template_args["dbg_path"] = 'error' + else: + template_args["dbg_path"] = 'error' + template_args["src_path"] = 'error' + template_args["libc_path"] = 'error' def do_generate(args: dict): from jinja2 import Template - - template = Template(open(os.path.expanduser(config["template"])).read()) - rendered_template = template.render( - filename=os.path.basename(args["target"]) + '_patched', - libcname=args.get("libc_path"), - host=args.get("host"), - port=args.get("port"), - debug_file_directory=args.get("dbg_path"), - source_dircetory=args.get("src_path"), - author=args.get("author"), - time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), - ) + import glob + # 展开模板目录路径 + template_dir = os.path.expanduser(config["template"]) + # 检查template是否是目录 + if os.path.isdir(template_dir): + # 获取目录下所有的.py文件作为模板选项 + template_files = glob.glob(os.path.join(template_dir, "*.py")) + if not template_files: + log_error(f"No template files found in {template_dir}") + exit(1) + log_info("Available template files:") + for i, template_file in enumerate(template_files, 1): + log_info(f"{i}. {os.path.basename(template_file)}") + while(1): + try: + choice = int(input("Please select a template number: ")) + if 1 <= choice <= len(template_files): + selected_template = template_files[choice - 1] + break + else: + log_info(f"Please enter a number between 1 and {len(template_files)}") + except ValueError: + log_info("Invalid number") + exit(1) + # 读取用户选择的模板文件 + log_info(f"Using template: {os.path.basename(selected_template)}") + template = Template(open(selected_template).read()) + else: + log_error("config template not a directory.") + exit(1) + try: + rendered_template = template.render( + filename=os.path.basename(args["target"])+ '_patched', + libcname=args.get("libc_path"), + host=args.get("host"), + port=args.get("port"), + debug_file_directory=args.get("dbg_path"), + source_dircetory=args.get("src_path"), + author=args.get("author"), + time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + ) + except Exception as e: + log_error(f"Error rendering template: {e}") + exit(1) if os.path.exists(config["script_name"]): if not prompt("Script exists, do you want to cover it?"): log_info("Haven't cover it. No script genarated.") @@ -539,7 +596,7 @@ def cli(ctx, verbose, config, threads, force): @cli.command(help="Initialize pwn game exploit enviroment.") @click.option("--host", help="Remote host.", default="127.0.0.1") -@click.option("--port", help="Remote port.", default="1337") +@click.option("--port", help="Remote port.", default="9999") @click.option("--nopatch", help="Just generate exp without patching elf.", is_flag=True, default=False) @click.option("--noexp", help="Just patch elf without generating exp.", is_flag=True, default=False) def init(host, port, nopatch:bool, noexp:bool): @@ -549,9 +606,13 @@ def init(host, port, nopatch:bool, noexp:bool): template_args["target"] = target_files[BaseFile.EXECUTABLE] if not nopatch: prepared_files = do_patch(target_files) - template_args["dbg_path"] = prepared_files.get(BaseFile.DBG) - template_args["src_path"] = prepared_files.get(BaseFile.SRC) - template_args["libc_path"] = prepared_files.get(BaseFile.LIBC) + if(prepared_files == 'ERROR'): + do_error_patch(target_files,template_args) + + else: + template_args["dbg_path"] = prepared_files.get(BaseFile.DBG) + template_args["src_path"] = prepared_files.get(BaseFile.SRC) + template_args["libc_path"] = prepared_files.get(BaseFile.LIBC) # generate exp if not noexp: template_args["host"] = host diff --git a/kernel_exploit/.gdbinit b/kernel_exploit/.gdbinit old mode 100644 new mode 100755 diff --git a/kernel_exploit/exp.c b/kernel_exploit/exp.c old mode 100644 new mode 100755 diff --git a/requirements.txt b/requirements.txt old mode 100644 new mode 100755 diff --git a/setup.sh b/setup.sh index f3f9fe3..a6d4252 100755 --- a/setup.sh +++ b/setup.sh @@ -3,8 +3,8 @@ echo "Start setup!" pip install -r requirements.txt sudo apt-get install patchelf mkdir -p ~/.config/cpwn -cp config.json ~/.config/cpwn/ -cp template.py ~/.config/cpwn/exp_template.py +cp config.json ~/.config/cpwn/config.json +cp -r ./template ~/.config/cpwn/template cp -r ./kernel_exploit ~/.config/cpwn/kernel_exploit chmod +x cpwn.py echo "Move cpwn to /usr/bin" diff --git a/template.py b/template.py deleted file mode 100644 index 263102c..0000000 --- a/template.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 - -''' - author: {{author}} - time: {{time}} -''' -from pwn import * - -filename = "{{filename}}" -libcname = "{{libcname}}" -host = "{{host}}" -port = {{port}} -container_id = "" -proc_name = "" -elf = context.binary = ELF(filename) -if libcname: - libc = ELF(libcname) -gs = ''' -b main -{% if debug_file_directory %}set debug-file-directory {{debug_file_directory}}{%endif%} -{% if source_dircetory %}set directories {{source_dircetory}}{%endif%} -''' - -def start(): - if args.GDB: - return gdb.debug(elf.path, gdbscript = gs) - elif args.REMOTE: - return remote(host, port) - elif args.DOCKER: - import docker - from os import path - p = remote(host, port) - client = docker.from_env() - container = client.containers.get(container_id=container_id) - processes_info = container.top() - titles = processes_info['Titles'] - processes = [dict(zip(titles, proc)) for proc in processes_info['Processes']] - target_proc = [] - for proc in processes: - cmd = proc.get('CMD', '') - exe_path = cmd.split()[0] if cmd else '' - exe_name = path.basename(exe_path) - if exe_name == proc_name: - target_proc.append(proc) - idx = 0 - if len(target_proc) > 1: - for i, v in enumerate(target_proc): - print(f"{i} => {v}") - idx = int(input(f"Which one:")) - import tempfile - with tempfile.NamedTemporaryFile(prefix = 'cpwn-gdbscript-', delete=False, suffix = '.gdb', mode = 'w') as tmp: - tmp.write(f'shell rm {tmp.name}\n{gs}') - print(tmp.name) - run_in_new_terminal(["sudo", "gdb", "-p", target_proc[idx]['PID'], "-x", tmp.name]) - return p - else: - return process(elf.path) - -p = start() - -# Your exploit here - -p.interactive() diff --git a/template/template.py b/template/template.py new file mode 100755 index 0000000..bf60bf0 --- /dev/null +++ b/template/template.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +''' + author: {{author}} + time: {{time}} +''' +from pwn import * +from time import sleep +filename = "{{filename}}" +libcname = "{{libcname}}" +host = "{{host}}" +port = {{port}} +elf = context.binary = ELF(filename) +context.terminal = ['tmux', 'neww'] +context(arch = 'amd64',log_level = 'debug',os = 'linux') +if libcname: + libc = ELF(libcname) +gs = ''' +b main +{% if debug_file_directory %}set debug-file-directory {{debug_file_directory}}{%endif%} +{% if source_dircetory %}set directories {{source_dircetory}}{%endif%} +''' + +def start(): + if args.GDB: + return gdb.debug(elf.path, gdbscript = gs) + elif args.REMOTE: + return remote(host, port) + else: + return process(elf.path) +#---------------------------------------------------# +r = lambda x:p.recv(x) +rl = lambda:p.recvline(keepends=True) +til = lambda x:p.recvuntil(x,drop=True) +s = lambda x:p.send(x) +sl = lambda x:p.sendline(x) +sa = lambda x,y:p.sendafter(x,y) +sla = lambda x,y:p.sendlineafter(x,y) +suc = lambda x,y:success(x+" -> "+y) +#---------------------------------------------------# +def db() : + gdb.attach(p) + pause() + +p = start() + +# Your exploit here + +p.interactive() diff --git a/template/template_docker.py b/template/template_docker.py new file mode 100644 index 0000000..9fe5576 --- /dev/null +++ b/template/template_docker.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +''' + author: {{author}} + time: {{time}} +''' +import docker.types +from pwn import * +import docker +from os import path +from pwn import * +from ctypes import * +from time import sleep +#docker run -it --rm -p 9999:9999 -p 10000:10000 --name --pid=host --cap-add=SYS_PTRACE ./run.sh +filename = "{{filename}}" +libcname = "{{libcname}}" +host = "{{host}}" +port = {{port}} +gdb_port = 10000 +# 基本设置 +elf = context.binary = ELF(filename) +context.terminal = ['tmux', 'neww'] +context(arch = 'amd64',log_level = 'debug',os = 'linux') +container_name = 'fedora42-1' # 镜像名 +run_cmd = "/bin/bash -c './run.sh'" # 容器启动命令 +# 加载libc +if libcname: + libc = ELF(libcname) + +#---------------------------------------------------# +r = lambda x:p.recv(x) +rl = lambda:p.recvline(keepends=True) +til = lambda x:p.recvuntil(x,drop=True) +s = lambda x:p.send(x) +sl = lambda x:p.sendline(x) +sa = lambda x,y:p.sendafter(x,y) +sla = lambda x,y:p.sendlineafter(x,y) +suc = lambda x,y:success(x+" -> "+y) +#---------------------------------------------------# + +if args.DOCKER: + client = docker.from_env() + container = client.containers.run( + container_name+":latest", + run_cmd, + detach=True, # 后台运行容器 + tty=True, # 分配伪终端 + stdin_open=True, # 允许容器接受输入 + ports={ # 映射端口 + "9999/tcp": 9999, + "10000/tcp": 10000 + }, + name= container_name, # 容器名 + pid_mode="host", # 设置容器共享宿主机的 PID 命名空间 + cap_add=["SYS_PTRACE"], # 添加容器权限 + remove=True # 容器停止后自动删除 + ) + p = remote(ip, port) + processes_info = container.top() + titles = processes_info['Titles'] + processes = [dict(zip(titles, proc)) for proc in processes_info['Processes']] + target_proc = [] + for proc in processes: + cmd = proc.get('CMD', '') + exe_path = (cmd.split()[0] if cmd else '') + exe_name = path.basename(exe_path) + if exe_name == filename: + target_proc.append(proc) + idx = 0 + if len(target_proc) > 1: + for i, v in enumerate(target_proc): + print(f"{i} => {v}") + idx = int(input(f"Which one:")) + cmd = f"gdbserver :{gdb_port} --attach {target_proc[idx]['PID']}" + exec_instance = container.exec_run(cmd, detach=True, tty=True) + run_in_new_terminal(f"gdb -ex \"target remote {ip}:{gdb_port}\"") +else: + p = remote(ip, port) +# Your exploit here + +p.interactive() \ No newline at end of file From 47a9741b0775223876bcee8ba4d0e5ffb8468a66 Mon Sep 17 00:00:00 2001 From: Squeasp123 Date: Mon, 6 Oct 2025 20:02:38 +0800 Subject: [PATCH 2/4] 1 --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 50637b4..0402061 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.git_history \ No newline at end of file +.gdb_history +.gitignore \ No newline at end of file From 75332abbc77913cb568d88f6a0b1252cc2aa656b Mon Sep 17 00:00:00 2001 From: Squeasp123 Date: Mon, 6 Oct 2025 20:21:01 +0800 Subject: [PATCH 3/4] Delete .gdb_history --- .gdb_history | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gdb_history diff --git a/.gdb_history b/.gdb_history deleted file mode 100644 index ea38b1f..0000000 --- a/.gdb_history +++ /dev/null @@ -1,2 +0,0 @@ -checksec -q From 328b9dee16ffe3442fc1b1f4255af5910ab3ba8d Mon Sep 17 00:00:00 2001 From: Squeasp123 Date: Mon, 6 Oct 2025 20:21:11 +0800 Subject: [PATCH 4/4] Delete .gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0402061..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.gdb_history -.gitignore \ No newline at end of file