This page uses every post component once, to show how each looks and works in a post, and so styles, scripts and performance can be checked in one place. All data is illustrative: addresses come from the documentation ranges, hosts are example.com names, and hashes, serials and timings are made up unless the text says otherwise.
Network
A raw request and its response, instead of a screenshot of a proxy's request pane:
POST /login HTTP/1.1
Host: app.example.com
Content-Type: application/x-www-form-urlencoded
user=alice&password=REDACTEDHTTP/1.1 303 See Other
Location: /
Set-Cookie: session=REDACTED; Path=/; Secure; HttpOnly; SameSite=LaxA packet list with its field tree and bytes, instead of a protocol analyzer screenshot:
| No. | Time | Source | Destination | Protocol | Length | Info |
|---|---|---|---|---|---|---|
| 1 | 0.000000 | 192.0.2.10 | 192.0.2.53 | DNS | 71 | Standard query 0x4a7c A example.com |
| 2 | 0.012204 | 192.0.2.53 | 192.0.2.10 | DNS | 87 | Standard query response 0x4a7c A example.com A 192.0.2.80 |
#1 · DNS · Standard query 0x4a7c A example.com
- Ethernet II, Src: 00:00:5e:00:53:0a, Dst: 00:00:5e:00:53:35
- Destination: 00:00:5e:00:53:35
- Source: 00:00:5e:00:53:0a
- Type: IPv4 (0x0800)
- Internet Protocol Version 4, Src: 192.0.2.10, Dst: 192.0.2.53
- 0100 .... = Version: 4
- .... 0101 = Header Length: 20 bytes (5)
- Time to Live: 64
- Protocol: UDP (17)
- Header Checksum: 0xda2e not verified
- Source Address: 192.0.2.10
- Destination Address: 192.0.2.53
- User Datagram Protocol, Src Port: 53001, Dst Port: 53
- Source Port: 53001
- Destination Port: 53
- Length: 37
- Checksum: 0x923b
- Domain Name System (query)
- Transaction ID: 0x4a7c
- Flags: 0x0100 Standard query
- 0... .... .... .... = Response: Message is a query
- .... ...1 .... .... = Recursion desired: Do query recursively
- Questions: 1
- Queries
- example.com: type A, class IN
- Name: example.com
- Type: A (1)
- Class: IN (0x0001)
- example.com: type A, class IN
Bytes and layouts
Named fields over a hex dump, instead of a hex editor screenshot:
EI_MAG0x00–0x03magic 0x7F followed by ASCII E, L, FEI_CLASS0x042 = ELFCLASS64EI_DATA0x051 = little-endiane_type0x10–0x113 = ET_DYN, also used by PIEe_machine0x12–0x130x3E = x86-64e_entry0x18–0x1Fentry point 0x1060
A C structure as bytes and a field table, instead of a struct diagram or pahole output:
| Offset | Name | Type | Size | Value |
|---|---|---|---|---|
| 0x00 | mchunk_prev_sizesize of the previous chunk while it is free | size_t | 8 | |
| 0x08 | mchunk_sizechunk size; low 3 bits are flags | size_t | 8 | 0x31 |
| 0x10 | fd | struct malloc_chunk * | 8 | 0x55555555a2c0 |
| 0x18 | bkoverwritten | struct malloc_chunk * | 8 | 0x4141414141414141 |
| 0x20 | fd_nextsize | struct malloc_chunk * | 8 | |
| 0x28 | bk_nextsize | struct malloc_chunk * | 8 |
The bits of a register, instead of a figure from a processor manual (flip a bit to see the fields decode):
| Bits | Field | Value |
|---|---|---|
| 63 | XDExecute disable | 1 |
| 62–59 | PKProtection key | 0x0 |
| 51–12 | AddressPhysical address of the page frame | 0x0000012345 |
| 8 | GGlobal | 0 |
| 7 | PAT | 0 |
| 6 | DDirty | 1 |
| 5 | AAccessed | 1 |
| 4 | PCD | 0 |
| 3 | PWT | 0 |
| 2 | U/S
| 1 |
| 1 | R/W
| 1 |
| 0 | PPresent | 1 |
A process tree, instead of a screenshot of a process explorer:
- explorer.exepid 4012user alice
- WINWORD.EXEpid 6120opened invoice.docm
- cmd.exepid 6644
- powershell.exepid 7020cmd powershell -nop -w hidden -enc …encoded command line
- conhost.exepid 7028
- powershell.exepid 7020cmd powershell -nop -w hidden -enc …encoded command line
- cmd.exepid 6644
- OneDrive.exepid 4388
- FileCoAuth.exepid 4502
- WINWORD.EXEpid 6120opened invoice.docm
Debugging and reversing
Disassembly with addresses and bytes, instead of a disassembler screenshot:
Debugger snapshots to step through, instead of debugger screenshots or a stepping GIF:
- Step 1/3before leave
rbp points at the saved frame pointer; the return address sits above it.
Code0x401136<add+16>8b 45 fcmoveax, dword ptr [rbp-0x4]current instruction: 0x401139<add+19>c9leave0x40113a<add+20>c3retRegisters- rax
- 0x2a
- rbp
- 0x7ffe3a8c1e40
- rsp
- 0x7ffe3a8c1e30
- rip
- 0x401139 <add+19>
Flags- ZF1
- PF1
StackRegisters pointing here Address Value Note rsp 0x7ffe3a8c1e30 0x0000000000000000 0x7ffe3a8c1e38 0x0000002a00000000 locals rbp 0x7ffe3a8c1e40 0x00007ffe3a8c1e60 saved rbp 0x7ffe3a8c1e48 0x0000000000401160 return address MemoryAddress Bytes 0x7ffe3a8c1e40 60 1e 8c 3a fe 7f 00 00 60 11 40 00 00 00 00 00 - Step 2/3after leave
leave is mov rsp, rbp then pop rbp.
Code0x401136<add+16>8b 45 fcmoveax, dword ptr [rbp-0x4]0x401139<add+19>c9leavecurrent instruction: 0x40113a<add+20>c3retRegisters- rax
- 0x2a
- rbp
- 0x7ffe3a8c1e60 (changed, was 0x7ffe3a8c1e40)
- rsp
- 0x7ffe3a8c1e48 (changed, was 0x7ffe3a8c1e30)
- rip
- 0x40113a <add+20> (changed, was 0x401139)
Flags- ZF1
- PF1
StackRegisters pointing here Address Value Note 0x7ffe3a8c1e30 0x0000000000000000 0x7ffe3a8c1e38 0x0000002a00000000 locals 0x7ffe3a8c1e40 0x00007ffe3a8c1e60 saved rbp rsp 0x7ffe3a8c1e48 0x0000000000401160 return address MemoryAddress Bytes 0x7ffe3a8c1e40 60 1e 8c 3a fe 7f 00 00 60 11 40 00 00 00 00 00 - Step 3/3after ret
ret pops the return address into rip.
Code0x401136<add+16>8b 45 fcmoveax, dword ptr [rbp-0x4]0x401139<add+19>c9leave0x40113a<add+20>c3retRegisters- rax
- 0x2a
- rbp
- 0x7ffe3a8c1e60
- rsp
- 0x7ffe3a8c1e50 (changed, was 0x7ffe3a8c1e48)
- rip
- 0x401160 <main+26> (changed, was 0x40113a)
Flags- ZF1
- PF1
StackAddress Value Note 0x7ffe3a8c1e30 0x0000000000000000 0x7ffe3a8c1e38 0x0000002a00000000 locals 0x7ffe3a8c1e40 0x00007ffe3a8c1e60 saved rbp 0x7ffe3a8c1e48 0x0000000000401160 return address MemoryAddress Bytes 0x7ffe3a8c1e40 60 1e 8c 3a fe 7f 00 00 60 11 40 00 00 00 00 00
A backtrace with the key frame marked and library frames folded, instead of a crash dialog screenshot:
- #0 (system frame)0x7f3a2b9a1f2flibc.so.6!__memmove_avx_unaligned_erms+0x2f
- #1 (system frame)0x7f3a2b9a2a5dlibc.so.6!__memcpy_chk+0x1d
- #2 (key frame)0x7f3a2c01d9e4libpng16.so.16!png_read_row+0x1c4pngread.c:512
row_buf holds 0x40 bytes, but the row is 0x200 bytes long.
- #30x7f3a2c01e1a0libpng16.so.16!png_read_image+0x5cpngread.c:720
- #40x55d0c0a01234viewer!load_image+0x9asrc/image.c:88
- #50x55d0c0a00f8aviewer!main+0x2asrc/main.c:31
- #6 (system frame)0x7f3a2b829d90libc.so.6!__libc_start_call_main+0x80
- #7 (system frame)0x7f3a2b829e40libc.so.6!__libc_start_main+0x89
- #80x55d0c0a00b55viewer!_start+0x25
A control-flow graph, instead of a screenshot of a disassembler's graph view:
0x401126 cmp esi, 0x10
0x401129 jne bad
0x40112b xor ecx, ecxNext: bad (true), loop (false).
0x40112d movzx eax, byte ptr [rdi+rcx]
0x401131 xor al, 0x5a
0x401133 cmp al, byte ptr [rdx+rcx]
0x401136 jne badNext: bad (true), next (false).
0x401145 xor eax, eax
0x401147 retNo successors.
0x401138 inc ecx
0x40113a cmp ecx, 0x10
0x40113d jl loopNext: loop (true), ok (false).
0x40113f mov eax, 1
0x401144 retNo successors.
An executable's headers, sections and imports, instead of a PE viewer screenshot:
- Arch
- x86-64
- Type
- EXE (console)
- Entry point
- 0x140001400
- Image base
- 0x140000000
- ASLR: on
- DEP: on
- CFG: off
- SafeSEHn/a
- Machine
- 0x8664
- AMD64
- NumberOfSections
- 4
- TimeDateStamp
- 0x66F2A1C0
- DllCharacteristics
- 0x8160
- HIGH_ENTROPY_VA | DYNAMIC_BASE | NX_COMPAT
| Name | RVA | Mem size | Offset | File size | Flags | Entropy | Note |
|---|---|---|---|---|---|---|---|
| .textEP | 0x00001000 | 0x1A2C | 0x00000400 | 0x1C00 | r-x | 6.21 | |
| .rdata | 0x00003000 | 0xF10 | 0x00002000 | 0x1000 | r-- | 4.87 | |
| .data | 0x00004000 | 0x640 | 0x00003000 | 0x200 | rw- | 1.02 | |
| .rsrc | 0x00005000 | 0x1E0 | 0x00003200 | 0x200 | r-- | 7.61 | compressed icon |
Entropy (bits/byte)< 1 sparse< 6.8 typical6.8–7.2 high≥ 7.2 packed or encrypted
KERNEL32.dll4
GetStdHandleWriteConsoleWExitProcessVirtualProtectchanges page protection at run time
VCRUNTIME140.dll2
memset__C_specific_handler
A process memory map, instead of a screenshot of vmmap or /proc/<pid>/maps in a terminal:
8 regions · 2.02 MiB mapped · 4 gaps · 1 W+X
- image5
- heap1
- private1
- stack1
- writable + executable
- marked
- unmapped (compressed)
| Start | End | Size | Perm | Type | Module / note |
|---|---|---|---|---|---|
| 0000555555554000 | 0000555555555000 | 4 KiB | r--p | image | /usr/local/bin/demo |
| 0000555555555000 | 0000555555556000 | 4 KiB | r-xp | image | /usr/local/bin/demo |
| 0000555555556000 | 0000555555558000 | 8 KiB | rw-p | image | /usr/local/bin/demo |
| 0000555555558000 | 0000555555559000 | 4 KiB | unmapped | ||
| 0000555555559000 | 000055555557a000 | 132 KiB | rw-p | heap | [heap] |
| 000055555557a000 | 00007ffff7d83000 | 42.7 TiB | unmapped | ||
| 00007ffff7d83000 | 00007ffff7dab000 | 160 KiB | r--p | image | /usr/lib/x86_64-linux-gnu/libc.so.6 |
| 00007ffff7dab000 | 00007ffff7f40000 | 1.58 MiB | r-xp | image | /usr/lib/x86_64-linux-gnu/libc.so.6 |
| 00007ffff7f40000 | 00007ffff7fbb000 | 492 KiB | unmapped | ||
| 00007ffff7fbb000 | 00007ffff7fbc000 | 4 KiB | rwxpW+X | private | RWX page from mmap(PROT_WRITE | PROT_EXEC) |
| 00007ffff7fbc000 | 00007ffffffde000 | 128 MiB | unmapped | ||
| 00007ffffffde000 | 00007ffffffff000 | 132 KiB | rw-p | stack | [stack] |
Code
A shell session where readers copy only the commands, instead of a terminal screenshot:
$ file ./hello
./hello: ELF 64-bit LSB pie executable, x86-64
$ id -u
1000Numbered notes on lines of code, instead of a screenshot with arrows drawn on it:
ssize_t n = read(fd, hdr, sizeof *hdr);
if (n != sizeof *hdr) return -1;
if (hdr->len > MAX_BODY) return -1;
body = malloc(hdr->len);readmay return fewer bytes than asked for, even on a regular file.- A short read is an error here;
nmay also be-1witherrnoset. - The length comes from the input: check it before it sizes an allocation.
A patch with word-level marks and a split view, instead of a screenshot of a code review:
Two listings side by side, instead of two screenshots next to each other:
.method public static check(I)Z
const/4 v0, 0x1
return v0
.end methodstatic boolean check(int x) {
return true;
}Data
A JSON document to fold and search, instead of a screenshot of a decoded token:
A sortable, filterable table with typed columns, instead of a spreadsheet screenshot:
| Port | Proto | Service | Banner | Last seen |
|---|---|---|---|---|
| 22 | tcp | ssh | OpenSSH_9.6 |
2025-03-02 |
| 53 | udp | domain | — | 2025-02-28 |
| 161 | udp | snmp | — | 2025-02-27 |
| 443 | tcp | https | nginx |
2025-03-02 |
| 3306 | tcp | mysql | 8.0.36 |
2025-03-01 |
| 8080 | tcp | http-alt | Werkzeug/3.0.1 |
2025-03-01 |
A chart drawn from the numbers, with its data table, instead of a chart image:
A log to filter by level and text, instead of a screenshot of a log console:
2025-03-02T09:14:00.120Z INFO [main] auth - listening on 127.0.0.1:8443
2025-03-02T09:14:07.004Z WARN [http-3] auth - login failed user=admin src=198.51.100.7
2025-03-02T09:14:07.513Z WARN [http-3] auth - login failed user=admin src=198.51.100.7
2025-03-02T09:14:08.020Z WARN [http-3] auth - login failed user=admin src=198.51.100.7
2025-03-02T09:14:08.533Z WARN [http-3] auth - login failed user=admin src=198.51.100.7
2025-03-02T09:14:09.041Z ERROR [http-3] auth - rate limit reached, blocking 198.51.100.7 for 900s
2025-03-02T09:14:31.870Z INFO [http-5] auth - login ok user=deploy src=192.0.2.24 mfa=totpFormulas in TeX instead of pictures of equations: inline, XOR cancels itself (), and on a line of their own:
Security artefacts
An advisory card whose badge follows the CVSS score, instead of a screenshot of a CVE page:
Out-of-bounds read in a sample ELF parsing library
A sample ELF parsing library reads out of bounds on a malformed e_shnum, which can crash the process.
- Affected
- < 2.4.1
- Fixed in
- 2.4.1
- CWE
- CWE-125
- Reported
- Confirmed
- Fixed
- Disclosed
Multi-engine scan results, instead of a screenshot of an online scanner (the sample is the EICAR test file; the engine names are made up):
58/66
eicar.com
58 of 66 engines flagged it as malicious, 1 as suspicious
- malicious 58
- suspicious 1
- undetected 7
- unsupported 4
- MD5
44d88612fea8a8f36de82e1278abb02f- SHA-1
3395856ce81f2b7382dee72602f798b642f14140- SHA-256
275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f
| Engine | Verdict | Detection | Version | Updated |
|---|---|---|---|---|
| Aegis | malicious | EICAR-Test-File (not a virus) | 4.2.1 | |
| Bastion | malicious | EICAR_Test_File | — | |
| Cinder | suspicious | Heur.TestString | — | — |
| Dagger | undetected | — | — | — |
| Ember | unsupported | — | — | — |
A certificate chain judged against a stated date, instead of a screenshot of a browser's certificate viewer:
- leafwww.example.com
- Subject
- CN=www.example.com, O=Example Corp, C=US
- Issuer
- CN=Example TLS RSA CA 2026, O=Example Trust, C=US
- Validity
- → 111 days left · 365-day period
- Key
- EC P-256
- Signature
- sha256WithRSAEncryption
- SANs
- DNS www.example.com
- DNS example.com
Detailsserial · 1 extension · usages
- Serial
04:7A:C1:9E:5B:20:3D:8F:61:0E:A4:C7:92:1B:58:E3- Key usage
- digitalSignature
- EKU
- serverAuth, clientAuth
- Extensions
- basicConstraints criticalCA:FALSE
issued by the next certificate
- intermediateExample TLS RSA CA 2026
- Subject
- CN=Example TLS RSA CA 2026, O=Example Trust, C=US
- Issuer
- CN=Example Root CA, O=Example Trust, C=US
- Validity
- → 1661 days left · 3652-day period
- Key
- RSA 2048
- Signature
- sha256WithRSAEncryption
issued by the next certificate
- rootExample Root CA
- Subject
- CN=Example Root CA, O=Example Trust, C=US
- Issuer
- CN=Example Root CA, O=Example Trust, C=US
- Validity
- → 1872 days left · 9132-day period
- Key
- RSA 4096
- Signature
- sha1WithRSAEncryption
Indicators of compromise, grouped and defanged, instead of a screenshot of a threat report table:
275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0fdropper (EICAR test file)first seen
192[.]0[.]2[.]44:8443C2 listener
2001[:]db8[:][:]44
update[.]example[.]comC2, resolves to the address belowfirst seen
hxxps://cdn[.]example[.]net/assets/app[.]js?v=3second stage
billing[@]example[.]testphishing sender
HKCU\Software\Microsoft\Windows\CurrentVersion\Run\ExampleSyncpersistence
Global\example-sync-7f3a
Narrative
A dated timeline, instead of a timeline slide:
- Reported Reported to the vendor
Proof of concept sent to security@example.com.
- +2 daysAcknowledged Vendor acknowledged the report
- +12 daysCVE assigned CVE-2024-XXXX reserved
- +2 daysFixed Fix developed and tested
→ · 37 days
- +43 daysReleased Firmware 2.4.1 released
- +31 daysDisclosed Advisory published
90 days after the report, as agreed.
Numbered steps with folded output, instead of a series of screenshots:
- 1
Start the vulnerable build
bash docker run --rm -p 127.0.0.1:8080:8080 example/fileserver:1.4.2 - 2
Request a file outside the web root
The server joins the path without normalising it:
bash curl -s --path-as-is 'http://127.0.0.1:8080/static/../../etc/hostname'Outputresponse2 lines
fileserver-7f3cresponseoutput fileserver-7f3c - 3
Confirm the fix
Version 1.4.3 answers
400 Bad Requestfor the same request.
The same task per platform, instead of one screenshot per system:
openssl s_client -connect example.com:443 -servername example.com </dev/null | openssl x509 -noout -datesPowerShell has no openssl; read the certificate from the connection:
$tcp = [Net.Sockets.TcpClient]::new("example.com", 443)
$tls = [Net.Security.SslStream]::new($tcp.GetStream())
$tls.AuthenticateAsClient("example.com")
$tls.RemoteCertificate.GetExpirationDateString()A sequence diagram drawn in the browser, instead of an exported drawing:
sequenceDiagram accTitle: A cross-site POST under SameSite=Lax accDescr: A page on evil.example submits a form to app.example.com; the browser sends no session cookie, and the server refuses. participant E as evil.example participant B as Browser participant A as app.example.com E->>B: auto-submitted form POST B->>A: POST /transfer (no session cookie) A-->>B: 403 Forbidden
A terminal recording that plays in the page, instead of a GIF:
An image, for what only a picture can show:
Compiler-style callouts for asides, pitfalls and the bug itself:
And a CTF flag behind a spoiler:
FLAG
flag{c0mp0n3nts_3v3rywh3r3}