pentesting 0.24.2 → 0.24.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,9 @@
1
- # Binary Exploitation (Pwn) Techniques
1
+ # Binary Exploitation (Pwn) — Comprehensive CTF Guide
2
+
3
+ > **Cross-ref**: exploit.md (shell strategy), evasion.md (bypass), shells.md (shell types)
4
+
5
+ ## Phase 0: Recon — Identify Protections
2
6
 
3
- ## Recon — Identify Protections
4
7
  ```
5
8
  Before exploiting, understand what you're dealing with:
6
9
  ├── file <binary> → architecture, linking, stripped?
@@ -10,117 +13,399 @@ Before exploiting, understand what you're dealing with:
10
13
  ├── strace ./<binary> → system calls
11
14
  ├── readelf -s <binary> → symbol table
12
15
  ├── objdump -d <binary> → disassembly (or use radare2/Ghidra)
13
- └── ldd <binary> → linked libraries + ASLR check
16
+ ├── ldd <binary> → linked libraries + ASLR check
17
+ └── readelf -l <binary> → segment permissions (RWX = shellcode!)
18
+ ```
19
+
20
+ ### Protection Cheat Sheet
21
+ ```
22
+ Protection Bypass Strategy
23
+ ────────── ─────────────────────────
24
+ No NX → Shellcode on stack/heap
25
+ NX enabled → ROP (ret2libc, ret2win, ret2csu, ret2dlresolve)
26
+ No PIE → Hardcoded addresses work directly
27
+ PIE enabled → Need address leak first, then calculate offsets
28
+ No Canary → Direct buffer overflow
29
+ Canary → Leak canary via format string, brute-force (forking server)
30
+ Partial RELRO → GOT overwrite possible
31
+ Full RELRO → GOT read-only, use __malloc_hook/__free_hook or stack
32
+ No ASLR → Fixed addresses (check: cat /proc/sys/kernel/randomize_va_space)
33
+ ASLR → Leak libc/stack/heap base, ret2plt, partial overwrite
34
+ FORTIFY → Some format string restrictions, limited buffer overflow
14
35
  ```
15
36
 
16
37
  ## Stack Buffer Overflow
38
+
17
39
  ```
18
40
  Classic BOF flow:
19
41
  1. Find overflow length:
20
42
  python3 -c "print('A'*100)" | ./<binary>
21
- → Use pattern_create to find exact offset:
43
+ → Use cyclic pattern to find exact offset:
44
+ # Pwntools (preferred):
45
+ from pwn import *
46
+ cyclic(200) # generate pattern
47
+ cyclic_find(0x6161616b) # find offset from crash value
48
+
49
+ # MSF:
22
50
  msf-pattern_create -l 200
23
51
  msf-pattern_offset -q <EIP_value>
24
52
 
25
- 2. Control EIP:
53
+ 2. Control EIP/RIP:
26
54
  python3 -c "print('A'*offset + 'BBBB')" | ./<binary>
27
55
  → EIP should be 0x42424242
28
56
 
29
57
  3. Find return address:
30
- ├── No NX: JMP ESP in binary or libc
58
+ ├── No NX: JMP ESP/RSP in binary or libc
31
59
  │ objdump -d <binary> | grep "jmp.*esp"
32
60
  ├── NX enabled: ROP (Return Oriented Programming)
33
61
  └── ASLR: ret2libc or leak libc address
34
62
 
35
63
  Pwntools template:
36
64
  from pwn import *
37
- p = process('./<binary>') # or remote('host', port)
65
+ context.binary = elf = ELF('./<binary>')
66
+ # p = process(elf.path) # local testing
67
+ p = remote('host', port) # remote exploit
68
+
38
69
  offset = <N>
39
- payload = b'A' * offset
40
- payload += p64(ret_addr) # or p32 for 32-bit
41
- payload += <shellcode_or_rop>
70
+ payload = flat(
71
+ b'A' * offset,
72
+ elf.symbols['win_function'], # or ROP chain
73
+ )
42
74
  p.sendline(payload)
43
75
  p.interactive()
44
76
  ```
45
77
 
46
78
  ## Return Oriented Programming (ROP)
79
+
47
80
  ```
48
81
  When NX is enabled (no shellcode execution on stack):
49
82
 
50
83
  Find gadgets:
51
84
  ├── ROPgadget --binary <binary> --ropchain
52
85
  ├── ropper -f <binary> --search "pop rdi"
53
- └── Common gadgets: pop rdi; ret, pop rsi; ret, ret (for alignment)
86
+ ├── pwntools: ROP(elf).find_gadget(['pop rdi', 'ret'])
87
+ └── Common gadgets: pop rdi; ret, pop rsi; pop r15; ret, ret (alignment)
54
88
 
55
- ret2libc:
56
- ├── Leak libc address calculate system() and "/bin/sh" offsets
57
- ├── Pwntools: libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
58
- │ system_addr = libc.symbols['system']
59
- bin_sh = next(libc.search(b'/bin/sh'))
60
- └── Payload: pop_rdi + bin_sh + system
89
+ ═══════════════════════════════════════
90
+ ret2libc (Most Common ROP in CTF):
91
+ ═══════════════════════════════════════
92
+ 1. Leak libc address:
93
+ ├── GOT leak via puts/printf: call puts@plt(got['puts'])
94
+ ├── Format string: %p leak stack/libc pointers
95
+ └── Info leak via other vuln
96
+ 2. Calculate libc base:
97
+ libc_base = leaked_addr - libc.symbols['puts']
98
+ 3. Build payload:
99
+ system = libc_base + libc.symbols['system']
100
+ bin_sh = libc_base + next(libc.search(b'/bin/sh'))
101
+ pop_rdi = <gadget_addr>
102
+ # 64-bit: pop rdi; ret → /bin/sh → system
103
+ # Alignment: add extra 'ret' gadget before system if needed
104
+
105
+ Pwntools automated:
106
+ from pwn import *
107
+ elf = ELF('./<binary>')
108
+ libc = ELF('./libc.so.6') # or target libc
109
+ rop = ROP(elf)
110
+ rop.call('puts', [elf.got['puts']]) # leak
111
+ rop.call(elf.symbols['main']) # return to main for stage 2
61
112
 
62
- ret2win pattern:
113
+ ═══════════════════════════════════════
114
+ ret2win (Simplest):
115
+ ═══════════════════════════════════════
63
116
  ├── Find a "win" function (prints flag, spawns shell)
64
117
  ├── Payload: padding + win_function_address
65
- └── With PIE: Need a leak first, then calculate offset
118
+ ├── With PIE: Need a leak first, then calculate offset
119
+ └── Check: objdump -t <binary> | grep -i "win\|flag\|shell\|cat"
120
+
121
+ ═══════════════════════════════════════
122
+ ret2csu (When Gadgets Are Scarce):
123
+ ═══════════════════════════════════════
124
+ ├── __libc_csu_init has universal gadgets for rdi, rsi, rdx
125
+ ├── Two-stage: set registers via csu pop, then call function
126
+ └── web_search("ret2csu tutorial") for detailed gadget chains
127
+
128
+ ═══════════════════════════════════════
129
+ ret2dlresolve (No Libc Needed):
130
+ ═══════════════════════════════════════
131
+ ├── Forge fake relocation entry to resolve arbitrary function
132
+ ├── pwntools: Ret2dlresolvePayload(elf, symbol="system", args=["/bin/sh"])
133
+ └── Works even without libc leak — powerful when binary is minimal
134
+
135
+ ═══════════════════════════════════════
136
+ SROP (Sigreturn Oriented Programming):
137
+ ═══════════════════════════════════════
138
+ ├── Use sigreturn syscall to set ALL registers at once
139
+ ├── Pwntools: SigreturnFrame() — set rip, rsp, rax, etc.
140
+ ├── Need: syscall gadget + sigreturn number in rax (0xf on x86_64)
141
+ └── Extremely powerful — single gadget controls entire register state
66
142
  ```
67
143
 
68
144
  ## Format String Vulnerability
145
+
69
146
  ```
70
147
  Detection: Send %x.%x.%x.%x → if hex values appear, vulnerable
71
148
 
149
+ ═══════════════════════════════════════
72
150
  Read memory:
73
- ├── %p.%p.%p... → leak stack values (find canary, addresses)
151
+ ═══════════════════════════════════════
152
+ ├── %p.%p.%p... → leak stack values (find canary, addresses, libc)
74
153
  ├── %N$p → read Nth argument directly
75
- └── %s → read string at address on stack
154
+ ├── %s → read string at address on stack
155
+ └── Find useful leaks:
156
+ ├── Stack canary (8 bytes, ends with \x00)
157
+ ├── Libc addresses (0x7f... on 64-bit)
158
+ ├── PIE base (calculate from code pointers)
159
+ └── Heap addresses
76
160
 
77
- Write memory (overwrite GOT, return address):
78
- ├── %n writes number of characters printed so far
79
- ├── %N$n → write to Nth argument
80
- ├── %hn write 2 bytes (short)
81
- ├── %hhn → write 1 byte
82
- └── Pwntools fmtstr_payload: simplifies format string writes
161
+ ═══════════════════════════════════════
162
+ Write memory (overwrite GOT, return address, hooks):
163
+ ═══════════════════════════════════════
164
+ ├── %n writes number of characters printed so far (4 bytes)
165
+ ├── %N$n → write to Nth argument
166
+ ├── %hn → write 2 bytes (short) — most used
167
+ ├── %hhn → write 1 byte — most precise
168
+ └── Targets:
169
+ ├── GOT entry (redirect function to win/system/one_gadget)
170
+ ├── __malloc_hook / __free_hook (trigger via malloc/free)
171
+ ├── Return address on stack
172
+ ├── .fini_array (called at exit)
173
+ └── atexit handlers
83
174
 
84
- Pwntools:
175
+ ═══════════════════════════════════════
176
+ Pwntools automation:
177
+ ═══════════════════════════════════════
85
178
  from pwn import *
86
- p = process('./<binary>')
179
+ # Automatic format string exploit
87
180
  payload = fmtstr_payload(offset, {target_addr: desired_value})
181
+ # Advanced: write multiple values
182
+ payload = fmtstr_payload(offset, {
183
+ elf.got['printf']: elf.symbols['win'], # redirect printf→win
184
+ })
88
185
  p.sendline(payload)
89
186
  ```
90
187
 
91
188
  ## Heap Exploitation
189
+
92
190
  ```
93
- Common techniques:
94
- ├── Use After Free (UAF): allocate → free → allocate same size → use old pointer
95
- ├── Double Free: free same chunk twice → overlapping allocations
96
- ├── Heap Overflow: overflow into next chunk metadata
97
- ├── Tcache poisoning (glibc 2.26+): corrupt tcache fd pointer
191
+ ═══════════════════════════════════════
192
+ Fundamental Heap Techniques:
193
+ ═══════════════════════════════════════
194
+
195
+ Use After Free (UAF):
196
+ ├── allocate → free → allocate same size → use old pointer
197
+ ├── The new allocation reuses freed chunk's memory
198
+ ├── If old pointer is still accessible → read/write freed data
199
+ └── Key: control what gets allocated in the freed slot
200
+
201
+ Double Free:
202
+ ├── free(A) → free(B) → free(A) → now A is in freelist twice
203
+ ├── Allocate: get A → write fd pointer → allocate → allocate (arbitrary addr!)
204
+ ├── GLIBC 2.29+: key field check → need to overwrite key or use different bins
205
+ └── Bypass: tcache count tampering, or use fastbin (if >= 7 chunks in tcache)
206
+
207
+ Heap Overflow:
208
+ ├── Overflow into next chunk's metadata (size, fd, bk)
209
+ ├── Modify size → overlapping chunks → controlled overlap
210
+ ├── Null byte overflow: shrink next chunk → unlink attack
211
+ └── Off-by-one: even 1 byte overflow can be lethal
212
+
213
+ ═══════════════════════════════════════
214
+ Tcache Attacks (glibc 2.26-2.35):
215
+ ═══════════════════════════════════════
216
+ Tcache poisoning:
217
+ ├── Corrupt tcache entry's fd pointer → arbitrary allocation
218
+ ├── GLIBC 2.32+: Safe-linking (PROTECT_PTR) → need heap base leak
219
+ │ fd = (chunk_addr >> 12) ^ target_addr ← key formula!
220
+ ├── Allocate at: __free_hook, __malloc_hook, GOT, stack
221
+ └── Once arbitrary write: system("/bin/sh") or one_gadget
222
+
223
+ Tcache count manipulation:
224
+ ├── Overflow into tcache_perthread_struct (at heap base)
225
+ ├── Set counts[size_index] to allow more frees or skips
226
+ └── Enables double-free even on newer glibc
227
+
228
+ ═══════════════════════════════════════
229
+ Fastbin Attacks (legacy, still relevant):
230
+ ═══════════════════════════════════════
98
231
  ├── Fastbin dup: double free in fastbin → arbitrary write
99
- └── House of Force: corrupt top chunk size arbitrary allocation
232
+ ├── Size check: target must have valid fastbin size in header
233
+ ├── Align to 0x7f byte in __malloc_hook area (libc)
234
+ └── Used when tcache is full (7+ chunks of same size freed)
235
+
236
+ ═══════════════════════════════════════
237
+ Unsorted Bin Attacks:
238
+ ═══════════════════════════════════════
239
+ ├── Unsorted bin leak: free large chunk → fd/bk points to main_arena
240
+ ├── main_arena is at known offset from libc base → libc leak!
241
+ ├── Unsorted bin attack (glibc <2.29): corrupt bk → write main_arena addr
242
+ └── Size: must be ≥ 0x90 to avoid fastbin/tcache
243
+
244
+ ═══════════════════════════════════════
245
+ Large Bin Attack:
246
+ ═══════════════════════════════════════
247
+ ├── Corrupt large bin fd_nextsize/bk_nextsize
248
+ ├── Write heap address to arbitrary location
249
+ ├── Useful for: overwrite mp_.tcache_bins, global_max_fast
250
+ └── Enables further exploitation chain
251
+
252
+ ═══════════════════════════════════════
253
+ House Techniques (Named Patterns):
254
+ ═══════════════════════════════════════
255
+ ├── House of Force → corrupt top chunk size → allocate to target
256
+ ├── House of Spirit → forge fake chunk → free it → allocate at target
257
+ ├── House of Lore → small bin corruption → arbitrary allocation
258
+ ├── House of Orange → forge unsorted bin chunk from top chunk
259
+ ├── House of Botcake → tcache + unsorted bin overlap (2.31+)
260
+ ├── House of Pig → largebin + tcache stashing → arbitrary write
261
+ ├── House of Banana → rtld_global abuse for exit-time RCE
262
+ ├── House of Kiwi → _IO_FILE vtable abuse (2.35+)
263
+ └── house of XXX → web_search("house of XXX heap exploitation")
100
264
 
101
- Debug with gdb + gef/pwndbg:
102
- ├── heap bins → show free chunk bins
103
- ├── heap chunks → show all chunks
104
- ├── vis_heap_chunks visual heap layout
105
- └── x/20gx <addr> examine memory
265
+ ═══════════════════════════════════════
266
+ Debugging heap with gdb:
267
+ ═══════════════════════════════════════
268
+ Use pwndbg or gef (NOT plain gdb):
269
+ ├── heap → overview of all chunks
270
+ ├── bins → show free chunk bins (tcache, fast, unsorted, small, large)
271
+ ├── vis_heap_chunks → visual heap layout (color-coded)
272
+ ├── tcachebins → tcache entries per size
273
+ ├── fastbins → fastbin entries
274
+ ├── x/20gx <addr> → examine raw memory
275
+ └── find_fake_fast <addr> → find valid fastbin sizes near target
106
276
  ```
107
277
 
108
278
  ## Shellcode
279
+
109
280
  ```
110
281
  When NX is disabled (rare in modern, common in CTF):
111
- ├── msfvenom -p linux/x64/exec CMD="/bin/sh" -f python
112
- ├── pwntools: shellcode = asm(shellcraft.sh())
113
- ├── Avoid null bytes: Use alternative instructions
114
- │ xor eax, eax (instead of mov eax, 0)
115
- └── Size constraints → use short shellcode or staged
282
+
283
+ Generate:
284
+ ├── pwntools: shellcode = asm(shellcraft.sh(), arch='amd64')
285
+ ├── msfvenom -p linux/x64/exec CMD="/bin/sh" -f python -b '\x00'
286
+ ├── Custom: smaller/badchar-free shellcode
287
+ └── Staged: small shellcode reads larger shellcode from stdin
288
+
289
+ Constraints:
290
+ ├── Avoid null bytes: xor rax, rax (not mov rax, 0)
291
+ ├── Size limit: use short shellcode (shell in ~30 bytes possible)
292
+ ├── Alphanumeric: use AE64 encoder for alphanum-only shellcode
293
+ ├── Seccomp: check allowed syscalls with seccomp-tools dump ./<binary>
294
+ │ ├── open+read+write only → read flag file to stdout
295
+ │ ├── No execve → openat + sendfile or mmap
296
+ │ └── Pwntools: shellcraft.open('flag.txt') + shellcraft.read(3, 'rsp', 100) + shellcraft.write(1, 'rsp', 100)
297
+ └── Write+Execute memory (mprotect): change stack/heap to RWX first
298
+ ```
299
+
300
+ ## Advanced: One-Gadget and Magic Gadgets
301
+
302
+ ```
303
+ one_gadget: single address in libc that spawns shell
304
+ ├── Tool: one_gadget libc.so.6
305
+ ├── Usually has constraints: [rsp+0x40] == NULL, etc.
306
+ ├── When to use: anytime you can redirect execution to libc
307
+ │ ├── __malloc_hook overwrite → trigger via malloc
308
+ │ ├── __free_hook overwrite → trigger via free
309
+ │ ├── GOT overwrite → trigger when function is called
310
+ │ ├── .fini_array overwrite → trigger at exit
311
+ │ └── Return address overwrite → trigger at function return
312
+ └── Try ALL one_gadgets — first one often doesn't work due to constraints
313
+ ```
314
+
315
+ ## Kernel Exploitation (Advanced CTF)
316
+
317
+ ```
318
+ Common kernel pwn patterns:
319
+ ├── Use after free in kernel module → overwrite function pointer
320
+ ├── Race condition (TOCTOU) → exploit copy_from_user race
321
+ ├── Stack overflow in ioctl handler → kernel ROP
322
+ ├── Integer overflow → buffer size miscalculation
323
+ └── NULL pointer dereference (if mmap_min_addr = 0)
324
+
325
+ Privilege escalation:
326
+ ├── commit_creds(prepare_kernel_cred(0)) → instant root
327
+ ├── modprobe_path overwrite → trigger via unknown file format
328
+ ├── struct cred overwrite → change uid/gid to 0
329
+ └── Namespace escape → ns_capable bypass
330
+
331
+ Protection bypass:
332
+ ├── KASLR: leak kernel addresses (dmesg, /proc/kallsyms, info leak)
333
+ ├── SMEP/SMAP: use kernel gadgets only (no userspace exec)
334
+ ├── KPTI: KPTI trampoline for return to userspace
335
+ └── Stack canary: leak via info leak or race
336
+ ```
337
+
338
+ ## Pwntools Essential Patterns
339
+
340
+ ```python
341
+ from pwn import *
342
+
343
+ # Setup
344
+ context.binary = elf = ELF('./<binary>')
345
+ context.log_level = 'debug' # verbose for debugging
346
+ libc = ELF('./libc.so.6')
347
+
348
+ # Connection
349
+ p = process(elf.path) # local
350
+ p = remote('challenge.ctf.example', 1337) # remote
351
+ p = gdb.debug(elf.path, 'b main') # with gdb
352
+
353
+ # I/O
354
+ p.sendline(b'input')
355
+ p.sendafter(b'prompt: ', b'input')
356
+ p.recvuntil(b'Address: ')
357
+ leak = int(p.recvline().strip(), 16)
358
+
359
+ # Packing
360
+ p64(0xdeadbeef) # 64-bit little-endian
361
+ p32(0xdeadbeef) # 32-bit little-endian
362
+ u64(b'\x00' * 8) # unpack 8 bytes to int
363
+
364
+ # ROP
365
+ rop = ROP(elf)
366
+ rop.call('puts', [elf.got['puts']])
367
+ rop.call('main')
368
+ print(rop.dump())
369
+
370
+ # Libc
371
+ libc.address = leaked_puts - libc.symbols['puts']
372
+ system = libc.symbols['system']
373
+ bin_sh = next(libc.search(b'/bin/sh\x00'))
374
+
375
+ # DynELF (automatic libc resolution without libc file)
376
+ d = DynELF(leak_func, elf=elf)
377
+ system = d.lookup('system', 'libc')
378
+ ```
379
+
380
+ ## Libc Database Lookup
381
+
382
+ ```
383
+ When you leak a libc address but don't know which libc version:
384
+ ├── libc.rip → search by function address suffix
385
+ ├── libc-database → github.com/niklasb/libc-database
386
+ ├── web_search("libc database online lookup")
387
+ └── Pwntools: from pwn import *; libc = LibcSearcher('puts', leaked_addr)
388
+
389
+ Once identified:
390
+ ├── Download matching libc.so.6
391
+ ├── libc = ELF('./libc.so.6')
392
+ ├── libc.address = leak - libc.symbols['known_function']
393
+ └── Now all offsets (system, /bin/sh, one_gadget, hooks) are calculable
116
394
  ```
117
395
 
118
396
  ## Common CTF Pwn Patterns
397
+
119
398
  ```
120
- ├── gets() / scanf("%s") always overflows → classic BOF
121
- ├── printf(user_input) → format stringread/write memory
122
- ├── Custom malloc heap challengefind corruption primitive
123
- ├── seccomprestricted syscallsuse allowed ones (open/read/write)
124
- ├── Binary with SUID bit exploit get that user's privileges
125
- └── Server binary on remote port connect and exploit live
399
+ VulnerabilityExploitation Flow:
400
+ ├── gets() / scanf("%s") always overflowsclassic BOF → ROP/ret2libc
401
+ ├── printf(user_input) format stringleak + arbitrary write
402
+ ├── Custom malloc manager heap challengefind corruption primitive
403
+ ├── Menu-driven program → heap note challengeUAF/double-free/overflow
404
+ ├── seccomp-restricted ORW (open-read-write) shellcode chain
405
+ ├── PIE + Canary + NX → need 2 vulns: leak (fmtstr) + overflow
406
+ ├── Forking server → brute-force canary byte-by-byte (no ASLR reset)
407
+ ├── Stack pivot → leave; ret → redirect RSP to controlled buffer
408
+ ├── Partial overwrite → overwrite last 1-2 bytes of return addr (bypass PIE partially)
409
+ ├── SUID binary → exploit → get that user's privileges
410
+ └── Server binary on port → connect and exploit live
126
411
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.24.2",
3
+ "version": "0.24.4",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
@@ -29,7 +29,7 @@
29
29
  "release:minor": "npm version minor && npm run build && npm run publish:token",
30
30
  "release:major": "npm version major && npm run build && npm run publish:token",
31
31
  "release:docker": "docker buildx build --platform linux/amd64,linux/arm64 -t agnusdei1207/pentesting:latest --push .",
32
- "check": "TMPDIR=/tmp npm run test && npm run build && npm run release:docker"
32
+ "check:docker": "TMPDIR=/tmp npm run test && npm run build && npm run release:docker && bash test.sh"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",