* **Bir siber güvenlik şirketinde mi çalışıyorsunuz? Şirketinizin HackTricks'te reklamını görmek ister misiniz? Ya da en son PEASS sürümüne erişmek veya HackTricks'i PDF olarak indirmek ister misiniz?** [**ABONELİK PLANLARI**](https://github.com/sponsors/carlospolop)'na göz atın!
* [**Resmi PEASS & HackTricks ürünlerine**](https://peass.creator-spring.com) sahip olun
* **[💬 Discord grubuna](https://discord.gg/hRep4RUj7f) katılın veya [telegram grubuna](https://t.me/peass) katılın veya beni Twitter'da takip edin 🐦[@carlospolopm](https://twitter.com/hacktricks\_live).**
C'de **`printf`**, bazı dizeleri **yazdırmak** için kullanılabilen bir işlevdir. Bu işlevin beklediği **ilk parametre**, **biçimleyicilerle** birlikte **ham metindir**. Beklenen **diğer parametreler**, ham metinden **biçimleyicileri yerine koymak için değerlerdir**.
Diğer zayıf işlevler **`sprintf()`** ve **`fprintf()`**'dir.
Zafiyet, bu işlevin **ilk argümanı olarak bir saldırgan metnin kullanıldığı zaman ortaya çıkar**. Saldırgan, **printf biçim dizisi yeteneklerini kötüye kullanarak** özel bir giriş oluşturabilir ve **herhangi bir adresindeki herhangi bir veriyi okuyup yazabilir**. Bu şekilde **keyfi kod yürütebilir** hale gelir.
Saldırganın `pr`**`intf` parametresini kontrol ettiğine dikkat edin, bu temelde girişi `printf` çağrıldığında yığında olacak anlamına gelir, bu da belirli bellek adreslerini yığında yazabileceği anlamına gelir.
Bu girişi kontrol eden bir saldırgan, yığında **rastgele adres ekleyebilecek ve `printf`'in bunlara erişmesini sağlayabilecek**. Bu davranışın nasıl kullanılacağı bir sonraki bölümde açıklanacaktır.
Biçimleyici **`%n$s`**'yi kullanarak **`printf`**'in **n pozisyonundaki adresi** almasını sağlamak ve ardından onu **bir dizeymiş gibi yazdırmak** mümkündür (0x00 bulunana kadar yazdır). Dolayısıyla, eğer ikili dosyanın temel adresi **`0x8048000`** ise ve kullanıcı girişinin yığında 4. pozisyonda başladığını biliyorsak, ikilinin başlangıcını şu şekilde yazdırmak mümkündür:
Girişinize ofseti bulmak için 4 veya 8 bayt (`0x41414141`) gönderebilir ve ardından **`%1$x`** ve **artırarak** değeri `A'ları` alana kadar artırabilirsiniz.
<details>
<summary>Brute Force printf ofseti</summary>
```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>
### Ne Kadar Faydalı
Keyfi okumalar şu amaçlar için faydalı olabilir:
- Bellekten **binary**'yi **dökme**
- Hassas **bilgilerin** saklandığı belleğin belirli bölümlerine erişme (örneğin canary'ler, şifreleme anahtarları veya özel şifreler gibi bu [**CTF zorluğunda**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
Biçimlendirici **`$<num>%n`** **belirtilen adres**teki **yazılan bayt sayısını** \<num> parametresinde yığında yazar. Bir saldırgan printf ile istediği kadar karakter yazabiliyorsa, **`$<num>%n`**'yi bir keyfi sayıyı bir keyfi adrese yazacak şekilde kullanabilir.
Neyse ki, 9999 sayısını yazmak için girişe 9999 "A" eklemek gerekmez, bunun yerine **`%.<num-yazma>%<num>$n`** biçimlendiricisini kullanarak **`<num-yazma>`** sayısını**`num` pozisyonu tarafından işaret edilen adrese** yazmak mümkündür.
Ancak, genellikle `0x08049724` gibi bir adres yazmak için (bu tek seferde yazılacak BÜYÜK bir sayıdır), **`$n`** yerine genellikle **`$hn`** kullanılır. Bu, **yalnızca 2 Bayt yazmaya** olanak tanır. Bu nedenle bu işlem iki kez yapılır, biri adresin en yüksek 2B'si için ve diğeri en düşük olanlar için.
Bu örnekte, amacımız daha sonra çağrılacak bir **fonksiyonun****GOT** tablosundaki **adresini üzerine yazmaktır**. Bununla birlikte, bu, diğer keyfi yazma yöntemlerini suiistimal edebilir:
Kullanıcıdan **argümanlarını alan bir fonksiyonun adresini****`system`** **fonksiyonuna işaret edecek şekilde üzerine yazacağız**.\
Bahsedildiği gibi, adresi yazmak için genellikle 2 adımda gereklidir: İlk olarak adresin 2 Bayt'ını yazarsınız ve ardından diğer 2'sini. Bunun için **`$hn`** kullanılır.
* 32 bit, relro yok, canary yok, nx, pie yok, bayt başına format dizgilerini kullanarak bayrağı yığından sızdırmak için temel kullanım (yürütme akışını değiştirmeye gerek yok)
* 32 bit, relro, canary yok, nx, pie yok, format dizgisi kullanarak `.fini_array` içinde main içinde bir adres yazma (bu nedenle akış 1 kez daha döner) ve GOT tablosundaki `system` adresini `strlen`'e işaret eden `system` adresini yazma. Akış main'e geri döndüğünde, kullanıcı girdisiyle `strlen` çalıştırılır ve `system`'e işaret ederse, geçilen komutları çalıştıracaktır.