Name | pwnkit JSON |
Version |
0.2.1
JSON |
| download |
home_page | None |
Summary | Axura's reusable pwn utilities, gadgets, debugging, shellcodes, templates |
upload_time | 2025-08-31 02:47:05 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | MIT License
Copyright (c) 2025 Axura
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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. |
keywords |
ctf
exploit
heap
pwn
pwntools
rop
stack
template
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# pwnkit
[](https://pypi.org/project/pwnkit/)
[](LICENSE)
[](https://pypi.org/project/pwnkit/)
Exploitation toolkit for pwn CTFs & Linux binary exploitation research.
Includes exploit templates, I/O helpers, ROP gadget mappers, pointer mangling utilities, curated shellcodes, exploit gadgets, House of Maleficarum, gdb/helper scripts, etc.
---
## Installation
From [PyPI](https://pypi.org/project/pwnkit/):
**Method 1**. Install into **current Python environment** (could be system-wide, venv, conda env, etc.). use it both as CLI and Python API:
```bash
pip install pwnkit
```
**Method 2**. Install using `pipx` as standalone **CLI tools**:
```bash
pipx install pwnkit
```
**Method 3.** Install from source (dev):
```bash
git clone https://github.com/4xura/pwnkit.git
cd pwnkit
pip install -e .
```
---
## Quick Start
### CLI
All options:
```bash
pwnkit -h
```
Create an exploit script template:
```bash
# local pwn
pwnkit xpl.py --file ./pwn --libc ./libc.so.6
# remote pwn
pwnkit xpl.py --file ./pwn --host 10.10.10.10 --port 31337
# Override default preset with individual flags
pwnkit xpl.py -f ./pwn -i 10.10.10.10 -p 31337 -A aarch64 -E big
# Minimal setup to fill up by yourself
pwnkit xpl.py
```
Example using default template:
```bash
$ pwnkit exp.py -f ./evil-corp -l ./libc.so.6 \
-A aarch64 -E big \
-a john.doe -b https://johndoe.com
[+] Wrote exp.py (template: pkg:default.py.tpl)
$ cat exp.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Title : Linux Pwn Exploit
# Author: john.doe - https://johndoe.com
#
# Description:
# ------------
# A Python exploit for Linux binex interaction
#
# Usage:
# ------
# - Local mode : python3 xpl.py
# - Remote mode : python3 [ <IP> <PORT> | <IP:PORT> ]
#
from pwnkit import *
from pwn import *
import os, sys
BIN_PATH = '/home/Axura/ctf/pwn/linux-user/evilcorp/evil-corp'
LIBC_PATH = '/home/Axura/ctf/pwn/linux-user/evilcorp/libc.so.6'
elf = ELF(BIN_PATH, checksec=False)
libc = ELF(LIBC_PATH) if LIBC_PATH else None
host, port = parse_argv(sys.argv[1:], None, None) # default local mode
ctx = Context(
arch = 'aarch64',
os = 'linux',
endian = 'big',
log_level = 'debug',
terminal = ('tmux', 'splitw', '-h') # remove when no tmux sess
).push()
io = Tube(
file_path = BIN_PATH,
libc_path = LIBC_PATH,
host = host,
port = port,
env = {}
).init().alias()
set_global_io(io) # s, sa, sl, sla, r, ru, uu64
init_pr("debug", "%(asctime)s - %(levelname)s - %(message)s", "%H:%M:%S")
def xpl():
# exploit chain here
io.interactive()
if __name__ == "__main__":
xpl()
```
List available built-in templates:
```bash
$ pwnkit -lt
[*] Bundled templates:
- default
- got
- heap
- minimal
- ret2libc
- ret2syscall
- setcontext
- srop
...
```
Use a built-in template:
```bash
pwnkit exp.py -t heap
```
### Python API
```python
from pwnkit import *
from pwn import *
# - Push a context preset
ctx = Context.preset("linux-amd64-debug")
"""
ctx = Context(
arch = "amd64"
os = "linux"
endian = "little"
log_level = "debug"
terminal = ("tmux", "splitw", "-h") # remove when no tmux
)
"""
ctx.push() # applies to pwntools' global context
# - Simple I/O stream
io = Tube(
file_path = "/usr/bin/sudoedit",
libc_path = "./libc.so.6",
host = "127.0.0.1",
port = 123456,
env = {}
).init().alias()
io.sl(b"hello")
print(io.r(5)) # b'hello'
# - Use io aliases globally
set_global_io(io)
sl(b"hello")
print(r(5)) # b'hello'
# - ROP after leaking libc_base
libc.address = libc_base
ggs = ROPGadgets(libc)
p_rdi_r = ggs['p_rdi_r']
p_rsi_r = ggs['p_rsi_r']
p_rax_r = ggs['p_rax_r']
p_rsp_r = ggs['p_rsp_r']
p_rdx_rbx_r = ggs['p_rdx_rbx_r']
leave_r = ggs['leave_r']
ret = ggs['ret']
...
# - libc Pointer protection
# 1) Pointer guard
guard = 0xdeadbeef # leak it or overwrite it
pg = PointerGuard(guard)
ptr = 0xcafebabe
enc_ptr = pg.mangle(ptr)
dec_ptr = pg.demangle(enc_ptr)
assert ptr == dec_ptr
# 2) Safe linking
# e.g., after leaking heap_base for tcache
slfd = SafeLinking(heap_base)
fd = 0x55deadbeef
enc_fd = slfd.encrypt(fd)
dec_fd = slfd.decrypt(enc_fd)
assert fd == dec_fd
# - Shellcode generation
# 1) List all built-in available shellcodes
for name in list_shellcodes():
print(" -", name)
# 2) Retrieve by arch + name, default variant (min)
sc = ShellcodeReigstry.get("amd64", "execve_bin_sh")
print(f"[+] Got shellcode: {sc.name} ({sc.arch}), {len(sc.blob)} bytes")
print(hex_shellcode(sc.blob)) # output as hex
# 3) Retrieve explicit variant
sc = ShellcodeReigstry.get("i386", "execve_bin_sh", variant=33)
print(f"[+] Got shellcode: {sc.name} ({sc.arch}), {len(sc.blob)} bytes")
print(hex_shellcode(sc.blob))
# 4) Retrieve via composite key
sc = ShellcodeReigstry.get(None, "amd64:execveat_bin_sh:29")
print(f"[+] Got shellcode: {sc.name}")
print(hex_shellcode(sc.blob))
# 5) Fuzzy lookup
sc = ShellcodeReigstry.get("amd64", "ls_")
print(f"[+] Fuzzy match: {sc.name}")
print(hex_shellcode(sc.blob))
# 6) Builder demo: reverse TCP shell (amd64)
builder = ShellcodeBuilder("amd64")
rev = builder.build_reverse_tcp_shell("127.0.0.1", 4444)
print(f"[+] Built reverse TCP shell ({len(rev)} bytes)")
print(hex_shellcode(rev))
...
io.interactive()
```
---
## Context Presets
Available presets (built-in):
* `linux-amd64-debug`
* `linux-amd64-quiet`
* `linux-i386-debug`
* `linux-i386-quiet`
* `linux-arm-debug`
* `linux-arm-quiet`
* `linux-aarch64-debug`
* `linux-aarch64-quiet`
* `freebsd-amd64-debug`
* `freebsd-amd64-quiet`
---
## Custom Templates
Templates (`*.tpl` or `*.py.tpl`) are rendered with a context dictionary.
Inside your template file you can use Python format placeholders (`{var}`) corresponding to:
| Key | Meaning |
| ------------- | ------------------------------------------------------------ |
| `{arch}` | Architecture string (e.g. `"amd64"`, `"i386"`, `"arm"`, `"aarch64"`) |
| `{os}` | OS string (currently `"linux"` or `"freebsd"`) |
| `{endian}` | Endianness (`"little"` or `"big"`) |
| `{log}` | Log level (e.g. `"debug"`, `"info"`) |
| `{term}` | Tuple of terminal program args (e.g. `("tmux", "splitw", "-h")`) |
| `{file_path}` | Path to target binary passed with `-f/--file` |
| `{libc_path}` | Path to libc passed with `-l/--libc` |
| `{host}` | Remote host (if set via `-i/--host`) |
| `{port}` | Remote port (if set via `-p/--port`) |
| `{io_line}` | Pre-rendered code line that initializes the `Tube` |
| `{author}` | Author name from `-a/--author` |
| `{blog}` | Blog URL from `-b/--blog` |
Use your own custom template (`*.tpl` or `*.py.tpl`):
```bash
pwnkit exp.py -t ./mytpl.py.tpl
```
Or put it in a directory and point `PWNKIT_TEMPLATES` to it:
```bash
export PWNKIT_TEMPLATES=~/templates
pwnkit exploit.py -t mytpl
```
For devs, you can also place your exploit templates (which is just a Python file of filename ending with `tpl` suffix) into [`src/pwnkit/templates`](https://github.com/4xura/pwnkit/tree/main/src/pwnkit/templates), before cloning and building to make a built-in. You are also welcome to submit a custom template there in this repo for a pull request!
---
## TODO
* Move the template feature under mode `template`
* Create other modes (when needed)
Raw data
{
"_id": null,
"home_page": null,
"name": "pwnkit",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "ctf, exploit, heap, pwn, pwntools, rop, stack, template",
"author": null,
"author_email": "Axura <asuraulord@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/b0/e4/1c3c81f74d6a180c7f9e7df2116721de3259c0a89956278a890fe5c5208d/pwnkit-0.2.1.tar.gz",
"platform": null,
"description": "# pwnkit\n\n[](https://pypi.org/project/pwnkit/)\n[](LICENSE)\n[](https://pypi.org/project/pwnkit/)\n\nExploitation toolkit for pwn CTFs & Linux binary exploitation research. \nIncludes exploit templates, I/O helpers, ROP gadget mappers, pointer mangling utilities, curated shellcodes, exploit gadgets, House of Maleficarum, gdb/helper scripts, etc.\n\n---\n\n## Installation\n\nFrom [PyPI](https://pypi.org/project/pwnkit/):\n\n**Method 1**. Install into **current Python environment** (could be system-wide, venv, conda env, etc.). use it both as CLI and Python API:\n\n```bash\npip install pwnkit\n```\n\n**Method 2**. Install using `pipx` as standalone **CLI tools**:\n\n```bash\npipx install pwnkit\n```\n\n**Method 3.** Install from source (dev):\n\n```bash\ngit clone https://github.com/4xura/pwnkit.git\ncd pwnkit\npip install -e .\n```\n\n---\n\n## Quick Start\n\n### CLI\n\nAll options:\n```bash\npwnkit -h\n```\nCreate an exploit script template:\n```bash\n# local pwn\npwnkit xpl.py --file ./pwn --libc ./libc.so.6 \n\n# remote pwn\npwnkit xpl.py --file ./pwn --host 10.10.10.10 --port 31337\n\n# Override default preset with individual flags\npwnkit xpl.py -f ./pwn -i 10.10.10.10 -p 31337 -A aarch64 -E big\n\n# Minimal setup to fill up by yourself\npwnkit xpl.py\n```\nExample using default template:\n```bash\n$ pwnkit exp.py -f ./evil-corp -l ./libc.so.6 \\\n -A aarch64 -E big \\\n -a john.doe -b https://johndoe.com\n[+] Wrote exp.py (template: pkg:default.py.tpl)\n\n$ cat exp.py\n#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# Title : Linux Pwn Exploit\n# Author: john.doe - https://johndoe.com\n#\n# Description:\n# ------------\n# A Python exploit for Linux binex interaction\n#\n# Usage:\n# ------\n# - Local mode : python3 xpl.py\n# - Remote mode : python3 [ <IP> <PORT> | <IP:PORT> ]\n#\n\nfrom pwnkit import *\nfrom pwn import *\nimport os, sys\n\nBIN_PATH = '/home/Axura/ctf/pwn/linux-user/evilcorp/evil-corp'\nLIBC_PATH = '/home/Axura/ctf/pwn/linux-user/evilcorp/libc.so.6'\nelf = ELF(BIN_PATH, checksec=False)\nlibc = ELF(LIBC_PATH) if LIBC_PATH else None\nhost, port = parse_argv(sys.argv[1:], None, None)\t# default local mode \n\nctx = Context(\n arch = 'aarch64',\n os = 'linux',\n endian = 'big',\n log_level = 'debug',\n terminal = ('tmux', 'splitw', '-h')\t# remove when no tmux sess\n).push()\n\nio = Tube(\n file_path = BIN_PATH,\n libc_path = LIBC_PATH,\n host = host,\n port = port,\n env = {}\n).init().alias()\nset_global_io(io) # s, sa, sl, sla, r, ru, uu64\n\ninit_pr(\"debug\", \"%(asctime)s - %(levelname)s - %(message)s\", \"%H:%M:%S\")\n\ndef xpl():\n\n # exploit chain here\n\n io.interactive()\n\nif __name__ == \"__main__\":\n xpl()\n```\nList available built-in templates:\n```bash\n$ pwnkit -lt\n[*] Bundled templates:\n - default\n - got\n - heap\n - minimal\n - ret2libc\n - ret2syscall\n - setcontext\n - srop\n ...\n```\nUse a built-in template:\n```bash\npwnkit exp.py -t heap\n```\n\n### Python API\n\n```python\nfrom pwnkit import *\nfrom pwn import *\n\n# - Push a context preset\nctx = Context.preset(\"linux-amd64-debug\")\n\"\"\"\nctx = Context(\n arch\t = \"amd64\"\n os\t\t = \"linux\"\n endian\t = \"little\"\n log_level = \"debug\"\n terminal = (\"tmux\", \"splitw\", \"-h\")\t# remove when no tmux\n)\n\"\"\"\nctx.push() # applies to pwntools' global context\n\n# - Simple I/O stream\nio = Tube(\n file_path = \"/usr/bin/sudoedit\",\n libc_path = \"./libc.so.6\",\n host = \"127.0.0.1\",\n port\t = 123456,\n env\t\t = {}\n).init().alias()\nio.sl(b\"hello\")\nprint(io.r(5)) # b'hello'\n\n# - Use io aliases globally\nset_global_io(io)\nsl(b\"hello\")\nprint(r(5)) # b'hello'\n\n# - ROP after leaking libc_base\nlibc.address = libc_base\nggs \t= ROPGadgets(libc)\np_rdi_r = ggs['p_rdi_r']\np_rsi_r = ggs['p_rsi_r']\np_rax_r = ggs['p_rax_r']\np_rsp_r = ggs['p_rsp_r']\np_rdx_rbx_r = ggs['p_rdx_rbx_r']\nleave_r = ggs['leave_r']\nret \t= ggs['ret']\n...\n\n# - libc Pointer protection\n# 1) Pointer guard\nguard = 0xdeadbeef\t# leak it or overwrite it\npg = PointerGuard(guard)\nptr = 0xcafebabe\nenc_ptr = pg.mangle(ptr)\ndec_ptr = pg.demangle(enc_ptr)\nassert ptr == dec_ptr\n\n# 2) Safe linking \n# e.g., after leaking heap_base for tcache\nslfd = SafeLinking(heap_base)\nfd = 0x55deadbeef\nenc_fd = slfd.encrypt(fd)\ndec_fd = slfd.decrypt(enc_fd)\nassert fd == dec_fd\n\n# - Shellcode generation\n# 1) List all built-in available shellcodes\nfor name in list_shellcodes():\n print(\" -\", name)\n\n# 2) Retrieve by arch + name, default variant (min)\nsc = ShellcodeReigstry.get(\"amd64\", \"execve_bin_sh\")\nprint(f\"[+] Got shellcode: {sc.name} ({sc.arch}), {len(sc.blob)} bytes\")\nprint(hex_shellcode(sc.blob)) # output as hex\n\n# 3) Retrieve explicit variant\nsc = ShellcodeReigstry.get(\"i386\", \"execve_bin_sh\", variant=33)\nprint(f\"[+] Got shellcode: {sc.name} ({sc.arch}), {len(sc.blob)} bytes\")\nprint(hex_shellcode(sc.blob))\n\n# 4) Retrieve via composite key\nsc = ShellcodeReigstry.get(None, \"amd64:execveat_bin_sh:29\")\nprint(f\"[+] Got shellcode: {sc.name}\")\nprint(hex_shellcode(sc.blob))\n\n# 5) Fuzzy lookup\nsc = ShellcodeReigstry.get(\"amd64\", \"ls_\")\nprint(f\"[+] Fuzzy match: {sc.name}\")\nprint(hex_shellcode(sc.blob))\n\n# 6) Builder demo: reverse TCP shell (amd64)\nbuilder = ShellcodeBuilder(\"amd64\")\nrev = builder.build_reverse_tcp_shell(\"127.0.0.1\", 4444)\nprint(f\"[+] Built reverse TCP shell ({len(rev)} bytes)\")\nprint(hex_shellcode(rev))\n\n\n\n...\n\nio.interactive() \n```\n\n---\n\n## Context Presets\n\nAvailable presets (built-in):\n\n* `linux-amd64-debug`\n* `linux-amd64-quiet`\n* `linux-i386-debug`\n* `linux-i386-quiet`\n* `linux-arm-debug`\n* `linux-arm-quiet`\n* `linux-aarch64-debug`\n* `linux-aarch64-quiet`\n* `freebsd-amd64-debug`\n* `freebsd-amd64-quiet`\n\n---\n\n## Custom Templates\n\nTemplates (`*.tpl` or `*.py.tpl`) are rendered with a context dictionary.\nInside your template file you can use Python format placeholders (`{var}`) corresponding to:\n\n | Key | Meaning |\n | ------------- | ------------------------------------------------------------ |\n | `{arch}` | Architecture string (e.g. `\"amd64\"`, `\"i386\"`, `\"arm\"`, `\"aarch64\"`) |\n | `{os}` | OS string (currently `\"linux\"` or `\"freebsd\"`) |\n | `{endian}` | Endianness (`\"little\"` or `\"big\"`) |\n | `{log}` | Log level (e.g. `\"debug\"`, `\"info\"`) |\n | `{term}` | Tuple of terminal program args (e.g. `(\"tmux\", \"splitw\", \"-h\")`) |\n | `{file_path}` | Path to target binary passed with `-f/--file` |\n | `{libc_path}` | Path to libc passed with `-l/--libc` |\n | `{host}` | Remote host (if set via `-i/--host`) |\n | `{port}` | Remote port (if set via `-p/--port`) |\n | `{io_line}` | Pre-rendered code line that initializes the `Tube` |\n | `{author}` | Author name from `-a/--author` |\n | `{blog}` | Blog URL from `-b/--blog` |\n\nUse your own custom template (`*.tpl` or `*.py.tpl`):\n```bash\npwnkit exp.py -t ./mytpl.py.tpl\n```\nOr put it in a directory and point `PWNKIT_TEMPLATES` to it:\n```bash\nexport PWNKIT_TEMPLATES=~/templates\npwnkit exploit.py -t mytpl\n```\nFor devs, you can also place your exploit templates (which is just a Python file of filename ending with `tpl` suffix) into [`src/pwnkit/templates`](https://github.com/4xura/pwnkit/tree/main/src/pwnkit/templates), before cloning and building to make a built-in. You are also welcome to submit a custom template there in this repo for a pull request!\n\n---\n\n## TODO\n\n* Move the template feature under mode `template`\n* Create other modes (when needed)\n",
"bugtrack_url": null,
"license": "MIT License\n \n Copyright (c) 2025 Axura\n \n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.",
"summary": "Axura's reusable pwn utilities, gadgets, debugging, shellcodes, templates",
"version": "0.2.1",
"project_urls": {
"Changelog": "https://github.com/4xura/pwnkit/releases",
"Homepage": "https://4xura.com",
"Issues": "https://github.com/4xura/pwnkit/issues",
"Repository": "https://github.com/4xura/pwnkit"
},
"split_keywords": [
"ctf",
" exploit",
" heap",
" pwn",
" pwntools",
" rop",
" stack",
" template"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "7bbd49436e66b09d3ff53bc31b7d26e1ae103cb0751585fadf3f9e29697e47be",
"md5": "1c72522eeaf490e53d64fe4ddb5a16c0",
"sha256": "abfccd976d46fe741f799927b79db3a97941e3368231dbc6cf512b2aa031dc0f"
},
"downloads": -1,
"filename": "pwnkit-0.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1c72522eeaf490e53d64fe4ddb5a16c0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 35463,
"upload_time": "2025-08-31T02:47:03",
"upload_time_iso_8601": "2025-08-31T02:47:03.947672Z",
"url": "https://files.pythonhosted.org/packages/7b/bd/49436e66b09d3ff53bc31b7d26e1ae103cb0751585fadf3f9e29697e47be/pwnkit-0.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "b0e41c3c81f74d6a180c7f9e7df2116721de3259c0a89956278a890fe5c5208d",
"md5": "e6f8441d1543a4adf99eca85cf98c2b1",
"sha256": "bc7b132eff3b253d40fc77dedaffe53033ae3db47438da66ea2fcf88c933977a"
},
"downloads": -1,
"filename": "pwnkit-0.2.1.tar.gz",
"has_sig": false,
"md5_digest": "e6f8441d1543a4adf99eca85cf98c2b1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 35473,
"upload_time": "2025-08-31T02:47:05",
"upload_time_iso_8601": "2025-08-31T02:47:05.135923Z",
"url": "https://files.pythonhosted.org/packages/b0/e4/1c3c81f74d6a180c7f9e7df2116721de3259c0a89956278a890fe5c5208d/pwnkit-0.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-31 02:47:05",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "4xura",
"github_project": "pwnkit",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "pwnkit"
}