λ¬Έμ : DreamHack β [CodeEngn] Malware L04 λΆλ₯: Misc (μ μ±μ½λ λΆμ) λμ΄λ: π₯ Silver 4 FLAG:
magic_quotes_gpc
μ΄ μ리μ¦λ λ³΄ν΅ μ μ±μ½λ μμ€ μ‘°κ°μ λμ Έ μ£Όκ³ "무μμ νλ ν¨μμΈκ°"λ₯Ό 묻λλ€. L03μ 10μ€μ§λ¦¬ 체ν¬μ¬ 루ν΄μ΄μκ³ L05λ 31μ€μ§λ¦¬ base64 μΈμ½λμλ€.
L04 λ λ€λ₯΄λ€. μ½λκ° ν μ€λ μλ€.
# show_desc.sh
#!/bin/sh
# λλ¦Όν΅ API μμ μ΄ λ¬Έμ μ μ λͺ©Β·λΆλ₯Β·μ€λͺ
λ§ λ½μ λ³Έλ€
python3 ~/Dev/Hacking_Project/_λꡬ/dreamhack_auto/fetch_desc.py 371 | python3 -c '
import sys, json
d = json.load(sys.stdin)
print("μ λͺ© :", d["title"].strip())
print("λΆλ₯ :", ", ".join(d["tags"]))
print("λμ΄λ :", d["tier_display"])
print("νΌ μ¬λ :", d["cnt_solvers"], "λͺ
")
print()
print("[λ¬Έμ μ€λͺ
]")
print(d["description"].strip())
print()
print("[ννΈ]", d["hints"] or "μμ")
'./show_desc.sh
μ§λ¬Έμ λ μ€μ΄λ€.
APM(Apache, PHP, MySQL) νκ²½μ μ¬μ΄νΈλ₯Ό μ΄μμ€μΈ Lμ¨ νμ¬ SQL Injection μ μ±μ½λμ 곡격μ λ°κ³ μλ€ PHP μ€μ νμΌμμ μ΄λ€ μ΅μ μ μ€μ ν΄μΌ μμ νκ°
ex) νμ μμλ μκ³ ννΈλ μλ€. κ°μ μ리μ¦μ λ€λ₯Έ λ¬Έμ λ€μ²λΌ λ΅μ μλ¬Έμ ν λ¨μ΄λ€.
λ¬Έμ κ°μ
| νλͺ© | λ΄μ© |
|---|---|
| λ¬Έμ λͺ | [CodeEngn] Malware L04 |
| λμ΄λ | π₯ Silver 4 |
| λΆλ₯ | Misc (μ μ±μ½λ λΆμ) |
| μ 곡 νμΌ | μμ β λ°°ν¬λ³Έμ΄ λΉμ΄ μλ€ |
| 묻λ κ² | APM μ€νμμ SQL Injection μ λ§λ php.ini μ΅μ νλ |
| ν΅μ¬ | magic_quotes_gpc β GET/POST/COOKIE μ 체μ addslashes() λ₯Ό μλ μ μ© |
νμ΄ νλ¦μ μ§§λ€. ν보λ₯Ό λ€μ― κ°λ‘ μ’νκ³ , κ·Έ μ€ SQL Injection κ³Ό μ§μ κ΄κ³λ κ²μ νλλΏμ΄λΌλ κ±Έ νμΈνκ³ , μ€μ λ‘ κ·Έλ°μ§ 2010λ κ²½ APM μ€νμ λμ»€λ‘ μΈμ λμ‘°νλ€.
π¬ λ°°ν¬λ³Έμ΄ λΉμ΄ μλ€
λ¨Όμ νμΌλΆν° λ°μλ€. μ리μ¦μ λ€λ₯Έ λ¬Έμ λ€μ .txt μμ€ μ‘°κ°μ΄ λ€μ΄ μμλ€.
# show_files.sh
#!/bin/sh
# λ°°ν¬λ³Έμ 무μμ΄ λ€μ΄ μλμ§ β μ΄ λ¬Έμ λ νμΌμ΄ μλ€
unzip -l challenge_371.zip
echo
echo "-- extracted/ --"
ls -la extracted/
file extracted/*./show_files.sh
no-public-files 0λ°μ΄νΈ νλ. λΆμν μ½λκ° μμΌλ μ΄ λ¬Έμ λ 리λ²μ±μ΄ μλλΌ
2000λ
λ νλ° PHP μ΄μ μμμ 묻λ λ¬Έμ λ€.
π§© λ°°κ²½ β μ "μ€μ νμΌ"μμ SQL Injection μ λ§λ
μ§κΈ κ°κ°μΌλ‘λ μ΄μν μ§λ¬Έμ΄λ€. SQL Injection μ 쿼리λ₯Ό λ§λλ μ½λμμ λ§λ κ²μ΄μ§ μλ² μ€μ μμ λ§μ μΌμ΄ μλλ€. ν리νμ΄λ μ€ν μ΄νΈλ¨ΌνΈλ₯Ό μ°λ©΄ λμ΄λ€.
κ·Έλ°λ° 2000λ
λ PHP μλ κ·Έλ° μ΅μ
μ΄ μ€μ λ‘ μμλ€. magic_quotes_gpc λ€.
μ΄ μ΅μ
μ΄ μΌμ Έ μμΌλ©΄ PHP λ μμ²μ΄ μ€ν¬λ¦½νΈμ λλ¬νκΈ° μ μ
$_GET Β· $_POST Β· $_COOKIE(GPC β Get/Post/Cookie) μ 체λ₯Ό νμ΄
μμλ°μ΄ν Β· ν°λ°μ΄ν Β· λ°±μ¬λμ Β· NUL μμ λ°±μ¬λμλ₯Ό λΆμΈλ€. addslashes() λ₯Ό μλμΌλ‘ λ리λ μ
μ΄λ€.
μ ν리μΌμ΄μ
μ½λλ ν κΈμλ μ λ°λλ€. λ°λλ 건 php.ini ν μ€μ΄λ€.
곡μ νΈμ€ν
μμ λ¨μ΄ μ§ κ²μν μλ°± κ°λ₯Ό νκΊΌλ²μ "μμ νκ²" λ§λ€ μ μλ€λ κ² λΉμμ λ
Όλ¦¬μλ€.
μ΄ μ΅μ
μ λμ€μ ν΅μ§Έλ‘ νκΈ°λλ€. PHP 5.3.0 μμ deprecated λκ³ , 5.4.0 μμλ μμ μμ΄μ‘λ€.
μ κ±°λ μͺ½μ php-src μ μ₯μμ PHP-5.4 λΈλμΉ UPGRADING νμΌμ κ·Έλλ‘ μ ν μλ€.
curl -s https://raw.githubusercontent.com/php/php-src/PHP-5.4/UPGRADING | grep -n -i -E "magic.quotes"
κ·Έλ¬λκΉ μ΄ λ¬Έμ μ μ λ΅μ μ§κΈμ μ‘΄μ¬νμ§ μλ μ΅μ μ΄λ€. λ¬Έμ κ° λ§λ€μ΄μ§ μμ μ μμμΌ νλ¦°λ€.
ν보λ₯Ό μ’νλ€
php.ini μμ 보μ κ΄λ ¨μΌλ‘ μμ£Ό κ±°λ‘ λλ νλͺ©μ λ€μ― κ°μ―€ λλ€. SQL Injection κ³Ό μ§μ λΏλ 건 νλλΏμ΄λ€.
| μ΅μ | 무μμ νλ | SQL Injection μ λ§λ |
|---|---|---|
register_globals | μμ² λ³μλ₯Ό μ μ λ³μλ‘ μλ λ±λ‘ | β λ³μ μ€μΌ(μΈμ¦ μ°νΒ·νμΌ ν¬ν¨)μ©. 쿼리 λ¬Έμμ΄κ³Ό λ¬΄κ΄ |
safe_mode | UID κΈ°μ€μΌλ‘ νμΌ μ κ·Ό μ ν | β νμΌ μμ€ν 격리 |
display_errors | μλ¬λ₯Ό νλ©΄μ μΆλ ₯ | β³ μλ¬ κΈ°λ° μΈμ μ μ μ 보λμ μ€μΌ λΏ, μΈμ μ μ체λ κ·Έλλ‘ |
allow_url_include | http:// κ²½λ‘λ₯Ό include νμ© | β RFI(μ격 νμΌ ν¬ν¨)μ© |
magic_quotes_gpc | GPC μ
λ ₯μ addslashes() μλ μ μ© | β λ°μ΄νλ₯Ό 리ν°λ΄λ‘ λ§λ λ€ |
λ΅μ magic_quotes_gpc λ€. μ¬κΈ°κΉμ§λ νλ§ λ΄λ λμ¨λ€.
λ¬Έμ λ κ·Έ λ€μμ΄λ€. μ΄λ° μ’ λ₯μ λ΅μ "λ€λ€ κ·Έλ κ² λ§νλκΉ"λ‘ λλκΈ° μ½λ€. μ€μ λ‘ λ§νλμ§, μ΄λκΉμ§ λ§νλμ§ λ³Έ μ μ΄ μμΌλ©΄ μ λ°λ§ μλ κ²μ΄λ€.
π§ͺ λ©μ μΈμ΄λ€ β μ νν Debian 6 μΈκ°
λ¨Όμ μ§κΈ PC μ PHP λ‘ μ¬νμ μλνλ€. μ λλ€.
# modern_php.sh
#!/bin/sh
# μ§κΈ PHP μλ magic_quotes κ° λ¨μ μμ§ μλ€λ κ²μ νμΈνλ€
php -v | head -1
echo
echo "-- ini_get('magic_quotes_gpc') --"
php -r 'var_dump(ini_get("magic_quotes_gpc"));'
echo
echo "-- php.ini μ νλͺ©μ΄ μλκ° --"
php -i | grep -ci magic_quotes
echo " (0 = νλͺ© μμ²΄κ° μμ)"
echo
echo "-- get_magic_quotes_gpc() νΈμΆ --"
php -r 'get_magic_quotes_gpc();' 2>&1 | head -3./modern_php.sh
ini_get() μ false, php -i μ νλͺ© μμ²΄κ° 0건, ν¨μλ μμ μλ€.
magic_quotes_gpc = On μ μ¨ λ£μ΄λ PHP 8 μ κ·Έλ° μ§μμλ₯Ό λͺ¨λ₯΄λ 무μνλ€.
κ·Έλμ κ·Έ μ΅μ μ΄ μ€μ λ‘ λμνλ λ§μ§λ§ μΈλλ‘ λ΄λ €κ°λ€. Debian 6 (squeeze) λ€. Apache 2.2.16 / PHP 5.3.3 / MySQL 5.1 β λ¬Έμ κ° μμ νλ APM μ€ν κ·Έ μ체λ€.
# lab/Dockerfile
# APM(Apache + PHP + MySQL) μ¬ν λ© β CodeEngn Malware L04
# magic_quotes_gpc λ PHP 5.3 μμ deprecated, 5.4 μμ μ κ±°λλ€.
# κ·Έλμ κ·Έ μ΅μ
μ΄ "μ€μ λ‘ λμνλ" λ§μ§λ§ μΈλμΈ Debian 6 (squeeze) λ₯Ό μ΄λ€.
# Apache 2.2.16 / PHP 5.3.3 / MySQL 5.1.73
FROM debian/eol:squeeze
# μλΉμ€κ° λΉλ μ€μ λ¨μ§ μλλ‘ (λ컀μλ init μ΄ μλ€)
RUN printf '#!/bin/sh\nexit 101\n' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d
RUN apt-get -o Acquire::Check-Valid-Until=false update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes \
apache2 libapache2-mod-php5 php5-cli php5-mysql mysql-server \
&& rm -rf /var/lib/apt/lists/*
COPY www/ /var/www/
COPY init.sql /root/init.sql
COPY start.sh /root/start.sh
RUN chmod +x /root/start.sh
EXPOSE 80
CMD ["/root/start.sh"]Acquire::Check-Valid-Until=false κ° νμν μ΄μ λ squeeze μ μ₯μμ Release νμΌμ΄
μ΄λ―Έ μ€λμ μ λ§λ£λκΈ° λλ¬Έμ΄λ€. policy-rc.d λ λΉλ μ€μ mysql-server μ postinst κ°
λ°λͺ¬μ λμ°λ €λ€ μ€ν¨νλ κ±Έ λ§λλ€.
컨ν μ΄λκ° λ° λ MySQL λ°μ΄ν° λλ ν 리λ₯Ό λ§λ€κ³ μ€ν€λ§λ₯Ό λ£μ λ€ μνμΉλ₯Ό ν¬κ·ΈλΌμ΄λλ‘ μ‘λλ€.
# lab/start.sh
#!/bin/sh
set -e
[ -d /var/lib/mysql/mysql ] || mysql_install_db --user=mysql >/dev/null 2>&1
/usr/bin/mysqld_safe >/var/log/mysqld_safe.log 2>&1 &
for i in $(seq 1 60); do mysqladmin ping >/dev/null 2>&1 && break; sleep 1; done
mysql < /root/init.sql
. /etc/apache2/envvars
exec /usr/sbin/apache2 -D FOREGROUNDμ€ν€λ§λ κ·Έ μμ νμ ν μ΄λΈ κ·Έλλ‘λ€. νλ¬Έ λΉλ°λ²νΈκΉμ§ ν¬ν¨ν΄μ.
-- lab/init.sql
CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARACTER SET utf8;
USE shop;
DROP TABLE IF EXISTS members;
CREATE TABLE members (
idx INT AUTO_INCREMENT PRIMARY KEY,
userid VARCHAR(32) NOT NULL,
userpass VARCHAR(64) NOT NULL,
email VARCHAR(64) NOT NULL,
is_admin TINYINT(1) NOT NULL DEFAULT 0
) ENGINE=InnoDB;
INSERT INTO members (userid, userpass, email, is_admin) VALUES
('admin', 'S3cr3t-4dm1n-p4ss', 'admin@l-shop.example', 1),
('guest', 'guest', 'guest@l-shop.example', 0),
('dizo', 'hunter2', 'dizo@l-shop.example', 0);# lab/up.sh
#!/usr/bin/env bash
# APM λ©μ λμ°κ³ μ€λΉλ λκΉμ§ κΈ°λ€λ¦° λ€ PHP/μνμΉ λ²μ μ νμΈνλ€.
set -eu
docker rm -f l04-apm >/dev/null 2>&1 || true
docker run -d --name l04-apm -p 127.0.0.1:8080:80 l04-apm
for i in $(seq 1 90); do curl -sf -m 3 http://127.0.0.1:8080/env.php >/dev/null 2>&1 && break; sleep 1; done
docker exec l04-apm apache2 -v | head -1
curl -s http://127.0.0.1:8080/env.php | head -2./lab/up.sh
Apache 2.2.16, PHP 5.3.3. λ¬Έμ κ° λ§νλ APM μ΄λ€.
php.ini μ κ΄λ ¨ νλͺ©λ€μ΄ μ€μ λ‘ μ΄λ€ κ°μΈμ§ 컨ν
μ΄λ μμμ μ§μ λ³Έλ€.
docker exec l04-apm grep -n "^magic_quotes\|^register_globals\|^safe_mode =\|^display_errors\|^allow_url_include" /etc/php5/apache2/php.ini
747νμ magic_quotes_gpc = Off. μ°λ¦¬κ° λ§μ§ μ€μ μ΄ ν μ€μ΄λ€.
π£ μ·¨μ½ν νμ΄μ§ β 2008λ μ PHP μ½λ
λ©μ μ¬λ¦° νμ΄μ§λ λ€ κ°λ€. μ λΆ κ·Έ μμ κ²μν μ½λμμ νν 보λ λͺ¨μμΌλ‘ μΌλ€. μ λ ₯μ λ°μ΄ν μμ κ·Έλλ‘ μ΄μ΄ λΆμ΄κ³ , μ΄μ€μΌμ΄νλ ν리νμ΄λ μ€ν μ΄νΈλ¨ΌνΈλ μλ€.
<?php
// lab/www/login.php
// L μ¨μ μΌνλͺ° β 2008λ
κ²½ APM μ¬μ΄νΈμμ ννλ λ‘κ·ΈμΈ μ²λ¦¬.
// μ
λ ₯μ κ·Έλλ‘ λ°μ΄ν μμ μ΄μ΄ λΆμΈλ€. μ΄μ€μΌμ΄νλ, ν리νμ΄λ μ€ν
μ΄νΈλ¨ΌνΈλ μλ€.
$conn = mysql_connect("localhost", "root", "");
mysql_select_db("shop", $conn);
$userid = $_GET['userid'];
$userpass = $_GET['userpass'];
$sql = "SELECT idx, userid, email, is_admin FROM members "
. "WHERE userid='$userid' AND userpass='$userpass'";
echo "magic_quotes_gpc = " . (get_magic_quotes_gpc() ? "On" : "Off") . "\n";
echo "SQL: $sql\n";
$res = mysql_query($sql, $conn);
if (!$res) { echo "MySQL error: " . mysql_error($conn) . "\n"; exit; }
$row = mysql_fetch_assoc($res);
if ($row) {
echo "LOGIN OK -> idx={$row['idx']} userid={$row['userid']} "
. "email={$row['email']} is_admin={$row['is_admin']}\n";
} else {
echo "LOGIN FAILED\n";
}
?>νμ΄μ§κ° μμ±λ 쿼리λ₯Ό κ·Έλλ‘ μΆλ ₯νκ² ν΄ λλ€. μ΅μ μ μΌ°μ λ λ¬Έμμ΄μ΄ μ΄λ»κ² λ¬λΌμ§λμ§κ° μ΄ λ¬Έμ μ μ λΆλΌμ, κ·Έκ±Έ νλ©΄μμ λ°λ‘ 보λ κ² λ«λ€.
κ²μ νμ΄μ§λ κ²°κ³Όλ₯Ό κ·Έλλ‘ λΏλ¦¬λ―λ‘ UNION SELECT λ‘ λ€λ₯Έ 컬λΌμ λμ΄μ¬ μ μλ€.
<?php
// lab/www/search.php
// μν κ²μ β κ²°κ³Όκ° νλ©΄μ κ·Έλλ‘ λμ€λ―λ‘ UNION SELECT λ‘ λ€λ₯Έ ν
μ΄λΈμ λμ΄μ¬ μ μλ€.
$conn = mysql_connect("localhost", "root", "");
mysql_select_db("shop", $conn);
$q = $_GET['q'];
$sql = "SELECT userid, email FROM members WHERE userid LIKE '%$q%'";
echo "magic_quotes_gpc = " . (get_magic_quotes_gpc() ? "On" : "Off") . "\n";
echo "SQL: $sql\n";
$res = mysql_query($sql, $conn);
if (!$res) { echo "MySQL error: " . mysql_error($conn) . "\n"; exit; }
while ($row = mysql_fetch_assoc($res)) {
echo " {$row['userid']} | {$row['email']}\n";
}
?>μΈ λ²μ§Έλ λμ€μ μΈ λ°λ‘λ€. νλΌλ―Έν°κ° μ«μλΌ λ°μ΄νλ‘ κ°μΈμ§ μμλ€.
<?php
// lab/www/idlookup.php
// μ«μ νλΌλ―Έν° β λ°μ΄νλ‘ κ°μΈμ§ μμλ€. magic_quotes_gpc κ° On μ΄μ΄λ μ¬κΈ°λ λͺ» λ§λλ€.
$conn = mysql_connect("localhost", "root", "");
mysql_select_db("shop", $conn);
$idx = $_GET['idx'];
$sql = "SELECT userid, email, is_admin FROM members WHERE idx=$idx";
echo "magic_quotes_gpc = " . (get_magic_quotes_gpc() ? "On" : "Off") . "\n";
echo "SQL: $sql\n";
$res = mysql_query($sql, $conn);
if (!$res) { echo "MySQL error: " . mysql_error($conn) . "\n"; exit; }
while ($row = mysql_fetch_assoc($res)) {
echo " {$row['userid']} | {$row['email']} | admin={$row['is_admin']}\n";
}
?>λ§μ§λ§μ μ€μ μνλ₯Ό νμΈνλ νμ΄μ§λ€.
<?php
// lab/www/env.php
// php.ini μμ μ€μ λ‘ λ¬΄μμ΄ μΌμ Έ μλμ§ νμΈνλ νμ΄μ§.
// ini_get() μ κΊΌμ§ λΆλ¦¬μΈμ λΉ λ¬Έμμ΄λ‘ λλ €μ£Όλ―λ‘ On/Off λ‘ νμ΄μ κ°μ΄ μ°λλ€.
$keys = array('magic_quotes_gpc', 'magic_quotes_runtime', 'register_globals',
'safe_mode', 'display_errors', 'allow_url_include');
echo "PHP " . phpversion() . " / " . php_sapi_name() . "\n";
echo "php.ini = " . php_ini_loaded_file() . "\n\n";
foreach ($keys as $k) {
$v = ini_get($k);
printf("%-22s = %-3s (ini_get μκ°: %s)\n", $k, ($v ? "On" : "Off"), var_export($v, true));
}
echo "\nget_magic_quotes_gpc() = " . var_export(get_magic_quotes_gpc(), true) . "\n";
if (isset($_GET['x'])) {
echo "\n\$_GET['x'] = " . $_GET['x'] . "\n";
echo "hex = " . bin2hex($_GET['x']) . "\n";
}
?>βΆπ μ½μ§ 1 β ini_get μ΄ Off λ₯Ό λΉ λ¬Έμμ΄λ‘ λλ €μ€λ€
μ²μ env.php λ var_export(ini_get($k), true) λ§ μ°μλ€. κ·Έλ¬λλ μ¬μ― νλͺ©μ΄ μ λΆ '' λ‘ λμλ€.
magic_quotes_gpc = ''
register_globals = ''
safe_mode = ''"μ€μ νμΌμ λͺ» μ½μλ" μΆμ΄ php_ini_loaded_file() μ λ€μ λ΄€λλ° κ²½λ‘λ λ©μ©‘νλ€.
ini_get() μ κΊΌμ§ λΆλ¦¬μΈ μ§μμλ₯Ό λΉ λ¬Έμμ΄λ‘ λλ €μ£Όλ κ² μ μ λμμ΄λ€. μΌλ©΄ '1' μ΄ λλ€.
λΉ λ¬Έμμ΄κ³Ό "νλͺ©μ΄ μμ"μ΄ νλ©΄μμ λκ°μ΄ 보μ΄λ νλ¨μ΄ μ μ λ€. κ·Έλμ On/Off λ‘ νμ΄ μ°κ³
μκ°μ κ΄νΈλ‘ κ°μ΄ μ°κ² κ³ μ³€λ€. λ€μμ PHP 8 κ³Ό λμ‘°ν λ μ΄ κ΅¬λΆμ΄ νμν΄μ§λ€ β
PHP 8 μ false λ₯Ό λλ €μ£Όκ³ 5.3 μ '' λ₯Ό λλ €μ€λ€. λ λ€ "κ±°μ§"μ΄μ§λ§ λ»μ΄ λ€λ₯΄λ€.
π― Off β μΈμ μ μΈ κ°κ° λ€ ν΅νλ€
곡격μ μ
μ΄λ€. λ°μ΄νλ‘ μ‘°κ±΄μ λ«λ μΈμ¦ μ°ν, UNION μΌλ‘ 컬λΌμ λ°κΏμΉλ κ²μ μΈμ μ
,
κ·Έλ¦¬κ³ λ°μ΄νκ° μ μ΄μ μλ μ«μ νλΌλ―Έν°.
# lab/attack.sh
#!/usr/bin/env bash
# APM λ©μ SQL Injection 3μ’
μ λμ§λ€. νλ©΄μλ php κ° μ€μ λ‘ λ§λ μΏΌλ¦¬κ° κ°μ΄ μ°νλ€.
# (1) λ°μ΄νλ‘ μ‘°κ±΄μ λ«κ³ λλ¨Έμ§λ₯Ό μ£Όμ μ²λ¦¬νλ μΈμ¦ μ°ν
# (2) UNION SELECT λ‘ λ€λ₯Έ 컬λΌμ λμ΄μ€λ κ²μ μΈμ μ
# (3) λ°μ΄νκ° μ μ΄μ μλ μ«μ νλΌλ―Έν°
set -u
B=http://127.0.0.1:8080
echo "### (0) νμ¬ php.ini μν"
curl -s "$B/env.php" | sed -n '1,9p'
echo
echo "### (1) λ‘κ·ΈμΈ μ°ν β userid=admin'-- "
curl -s -G "$B/login.php" --data-urlencode "userid=admin'-- " --data-urlencode "userpass=x"
echo
echo "### (2) UNION β q=' UNION SELECT userid,userpass FROM members#"
curl -s -G "$B/search.php" --data-urlencode "q=' UNION SELECT userid,userpass FROM members#"
echo
echo "### (3) μ«μ νλΌλ―Έν° β idx=1 OR 1=1"
curl -s -G "$B/idlookup.php" --data-urlencode "idx=1 OR 1=1"./lab/attack.sh
μ λ€ ν΅νλ€.
λ‘κ·ΈμΈ μͺ½μ userid=admin'-- μ΄ λ§λ€μ΄ λΈ μΏΌλ¦¬κ° μ΄λ κ² λλ€.
SELECT idx, userid, email, is_admin FROM members WHERE userid='admin'-- ' AND userpass='x'μ°λ¦¬κ° λ£μ λ°μ΄νκ° userid λ¬Έμμ΄μ λ«μ λ²λ Έκ³ , κ·Έ λ€ -- λΆν°λ μ£Όμμ΄λΌ
λΉλ°λ²νΈ μ‘°κ±΄μ΄ ν΅μ§Έλ‘ μ¬λΌμ§λ€. is_admin=1 μΈ κ΄λ¦¬μ νμ΄ κ·Έλλ‘ λμ¨λ€.
κ²μ μͺ½μ λ λμλ€.
SELECT userid, email FROM members WHERE userid LIKE '%' UNION SELECT userid,userpass FROM members#%'λ λ²μ§Έ μ»¬λΌ μ리μ email λμ userpass λ₯Ό λΌμ λ£μμΌλ νλ¬Έ λΉλ°λ²νΈκ° νλ©΄μ μ°νλ€.
S3cr3t-4dm1n-p4ss Β· hunter2 κ° κ·Έλλ‘ λ³΄μΈλ€.
β On β php.ini ν μ€
μ΄μ μ΅μ λ§ μΌ λ€. μ ν리μΌμ΄μ μ½λλ 건λλ¦¬μ§ μλλ€.
# lab/mq.sh
#!/usr/bin/env bash
# php.ini μ magic_quotes_gpc λ₯Ό On/Off λ‘ λ°κΎΈκ³ μνμΉλ₯Ό λ€μ μ½νλ€.
# 컨ν
μ΄λ μ΄λ¦μ l04-apm, php.ini λ /etc/php5/apache2/php.ini λ€.
set -eu
VAL="$1" # on | off
docker exec l04-apm sed -i \
"s/^magic_quotes_gpc = .*/magic_quotes_gpc = ${VAL}/" /etc/php5/apache2/php.ini
docker exec l04-apm grep -n '^magic_quotes_gpc' /etc/php5/apache2/php.ini
docker exec l04-apm /usr/sbin/apache2ctl graceful
sleep 1./lab/mq.sh on
κ°μ 곡격μ λ€μ λμ§λ€.
./lab/attack.sh
μΏΌλ¦¬κ° μ΄λ κ² λ°λμλ€.
SELECT idx, userid, email, is_admin FROM members WHERE userid='admin\'-- ' AND userpass='x'λ°μ΄ν μμ λ°±μ¬λμκ° λΆμλ€. MySQL μ μ΄κ±Έ λ¬Έμμ΄μ λ«λ κΈ°νΈκ° μλλΌ
λ°μ΄νλΌλ κΈμ μμ²΄λ‘ μ½λλ€. κ·Έλμ μ‘°κ±΄μ΄ μ λκΈ°κ³ userid κ° admin'-- μΈ νμμ μ°Ύλ€κ°
μμΌλ LOGIN FAILED. UNION μͺ½λ κ°μ μ΄μ λ‘ 0νμ΄λ€.

μ ν리μΌμ΄μ μ κ·Έλλ‘λ€. λ°λ 건 μ€μ ν μ€μ΄λ€. λ¬Έμ κ° "μ€μ νμΌμμ 무μμ μ€μ ν΄μΌ μμ νκ°"λΌκ³ 묻λ μ΄μ κ° μ¬κΈ° μλ€.
π³οΈ κ·Έλ°λ° μ΄κ±΄ μμ ν λ°©μ΄κ° μλλ€
κ°μ νλ©΄ λ§μ§λ§ μ€μ λ€μ 보μ. magic_quotes_gpc = On μΈλ°λ μΈ λ²μ§Έ 곡격μ ν΅κ³Όνλ€.
SELECT userid, email, is_admin FROM members WHERE idx=1 OR 1=1addslashes() λ λ°μ΄νΒ·λ°±μ¬λμΒ·NUL μλ§ λ°±μ¬λμλ₯Ό λΆμΈλ€.
1 OR 1=1 μλ κ·Έλ° κΈμκ° νλλ μλ€. μ μ΄μ νλΌλ―Έν°λ₯Ό λ°μ΄νλ‘ κ°μΈμ§ μμμΌλ
λ§μ λμ μμ²΄κ° μλ€.
λ λ²μ§Έ ꡬλ©μ λ κ³ μ½νλ€. μ°κ²° λ¬Έμμ μ΄ λ©ν°λ°μ΄νΈλ©΄ λ°±μ¬λμκ° ν΅μ§Έλ‘ λ¨Ήνλ€.
<?php
// lab/www/gbk.php
// μ°κ²° λ¬Έμμ
μ΄ λ©ν°λ°μ΄νΈ(GBK)μΌ λ β addslashes κ° λ£μ λ°±μ¬λμκ° λ°μ΄νλ₯Ό λͺ» μ§ν¨λ€.
// 0xbf + 0x5c λ GBK μμ κΈμ ν κ°λ‘ λ¨Ήνλ―λ‘ λ°±μ¬λμκ° μ¬λΌμ§κ³ λ°μ΄νλ§ λ¨λλ€.
$conn = mysql_connect("localhost", "root", "");
mysql_select_db("shop", $conn);
mysql_query("SET NAMES gbk", $conn); // 2000λ
λ νμ€μΌ μ¬μ΄νΈμμ ννλ μ€μ
$userid = $_GET['userid'];
$sql = "SELECT idx, userid, email, is_admin FROM members WHERE userid='$userid' AND userpass='x'";
// mysql_client_encoding() μ SET NAMES λ₯Ό λ°μνμ§ μμΌλ―λ‘ μλ²μ μ§μ λ¬Όμ΄λ³Έλ€
$v = mysql_fetch_assoc(mysql_query("SHOW VARIABLES LIKE 'character_set_client'", $conn));
echo "magic_quotes_gpc = " . (get_magic_quotes_gpc() ? "On" : "Off") . "\n";
echo "character_set_client = " . $v['Value'] . "\n";
echo "userid hex = " . bin2hex($userid) . " (bf 5c 27 : 5c κ° bf μ λ¨Ήνλ€)\n";
echo "SQL: $sql\n";
$res = mysql_query($sql, $conn);
if (!$res) { echo "MySQL error: " . mysql_error($conn) . "\n"; exit; }
$row = mysql_fetch_assoc($res);
if ($row) {
echo "LOGIN OK -> idx={$row['idx']} userid={$row['userid']} is_admin={$row['is_admin']}\n";
} else {
echo "LOGIN FAILED\n";
}
?>0xbf λ₯Ό λ°μ΄ν μμ λΆμ¬ 보λΈλ€. addslashes() λ 0xbf 0x5c 0x27 μ λ§λ λ€.
κ·Έλ°λ° GBK μμ 0xbf 0x5c λ κΈμ ν κ°λ€. λ°±μ¬λμκ° κ·Έ κΈμμ ν‘μλκ³ λ°μ΄νλ§ λ¨λλ€.
curl -s "http://127.0.0.1:8080/gbk.php?userid=%bf%27%20OR%201%3D1%23"
magic_quotes_gpc = On μΈλ° LOGIN OK, is_admin=1. λ°±μ¬λμλ λΆλͺ
ν λΆμλλ°(bf5c27)
μ무 μμ©μ΄ μλ€.
βΆπ μ½μ§ 2 β mysql_client_encoding() μ λ―Ώμλ€κ° νλ¨μ κ·Έλ₯΄μΉ λ»νλ€
μ²μ gbk.php λ mysql_client_encoding($conn) μΌλ‘ λ¬Έμμ
μ μ°μλ€. κ²°κ³Όλ latin1 μ΄μλ€.
magic_quotes_gpc = On
charset = latin1SET NAMES gbk λ₯Ό λΆλͺ
ν 보λλλ° latin1 μ΄λΌλ, μ°νκ° μ±κ³΅ν κ² λ€λ₯Έ μ΄μ λλ¬ΈμΈκ° μΆμλ€.
mysql_client_encoding() μ ν΄λΌμ΄μΈνΈ λΌμ΄λΈλ¬λ¦¬κ° λ€κ³ μλ κ°μ λλ €μ£Όλλ°,
SET NAMES λ μλ² μͺ½ μΈμ
λ³μλ§ λ°κΎΈλ―λ‘ κ·Έ κ°μ΄ κ°±μ λμ§ μλλ€.
μλ²μ μ§μ λ¬Όμ΄λ΄μΌ νλ€.
SHOW VARIABLES LIKE 'character_set_client'μ΄λ κ² λ°κΎΈλ gbk κ° λμλ€. μ°νκ° ν΅ν μ΄μ κ° λ§μλ€. μ§λ¨ ν¨μ νλλ₯Ό μλͺ» 골λλ€κ³
"νμ ν΄μ"κΉμ§ νμ΄μ§ λ»νλ€.
λ λ°λ‘λ₯Ό ν©μΉλ©΄ κ²°λ‘ μ΄ μ΄λ κ² λλ€. magic_quotes_gpc λ λΉμ κΈ°μ€μΌλ‘ λ§λ λ΅μ΄κ³
μ€μ λ‘ λ°μ΄ν κΈ°λ° μΈμ μ
μ λ§μ§λ§, μ«μ νλΌλ―Έν°μ λ©ν°λ°μ΄νΈ λ¬Έμμ
μμμλ κ·Έλ₯ λ«λ¦°λ€.
PHP κ° μ΄ μ΅μ
μ 5.4 μμ μμ€ μ΄μ μ΄κΈ°λ νλ€ β μΌ λμΌλ©΄ μμ νλ€λ μ°©κ°μ λ§λ λ€.
π ν λ°© μ¬ν
λ© κ΅¬μ±λΆν° λμ‘°κΉμ§ μ€ν¬λ¦½νΈ νλλ‘ λ¬Άμλ€. μ΄λ―Έμ§λ₯Ό λ§λ€κ³ , 컨ν μ΄λλ₯Ό λμ°κ³ , Off/On κ°κ°μΌλ‘ 곡격μ λμ§κ³ , μμκ³Ό λ€λ₯΄λ©΄ κ·Έ μ리μμ μ€ν¨λ‘ λλλ€.
# reproduce.sh
#!/usr/bin/env bash
# [CodeEngn] Malware L04 β ν λ°© μ¬ν.
# APM(Apache 2.2 + PHP 5.3.3 + MySQL 5.1) λ©μ μΈμ°κ³ magic_quotes_gpc Off/On μ λμ‘°ν΄
# "php.ini μμ μ΄ μ΅μ
μ μΌλ©΄ SQL Injection μ΄ λ§νλ€"λ₯Ό μ€μ λ‘ νμΈν λ€ λ΅μ μΆλ ₯νλ€.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
EXPECT='magic_quotes_gpc'
B=http://127.0.0.1:8080
docker image inspect l04-apm >/dev/null 2>&1 || docker build -t l04-apm ./lab
docker rm -f l04-apm >/dev/null 2>&1 || true
docker run -d --name l04-apm -p 127.0.0.1:8080:80 l04-apm >/dev/null
for i in $(seq 1 90); do curl -sf -m 3 "$B/env.php" >/dev/null 2>&1 && break; sleep 1; done
fail() { echo "β FAIL β $1"; docker rm -f l04-apm >/dev/null 2>&1 || true; exit 1; }
./lab/mq.sh off >/dev/null
OFF_LOGIN=$(curl -s -G "$B/login.php" --data-urlencode "userid=admin'-- " --data-urlencode "userpass=x")
OFF_UNION=$(curl -s -G "$B/search.php" --data-urlencode "q=' UNION SELECT userid,userpass FROM members#")
echo "$OFF_LOGIN" | grep -q 'LOGIN OK' || fail "Off μΈλ° λ‘κ·ΈμΈ μ°νκ° μ λλ€"
echo "$OFF_UNION" | grep -q 'S3cr3t-4dm1n-p4ss' || fail "Off μΈλ° UNION μΌλ‘ λΉλ°λ²νΈκ° μ μμ΄ λμλ€"
./lab/mq.sh on >/dev/null
ON_LOGIN=$(curl -s -G "$B/login.php" --data-urlencode "userid=admin'-- " --data-urlencode "userpass=x")
ON_UNION=$(curl -s -G "$B/search.php" --data-urlencode "q=' UNION SELECT userid,userpass FROM members#")
ON_NUM=$(curl -s -G "$B/idlookup.php" --data-urlencode "idx=1 OR 1=1")
ON_GBK=$(curl -s "$B/gbk.php?userid=%bf%27%20OR%201%3D1%23")
echo "$ON_LOGIN" | grep -q 'LOGIN FAILED' || fail "On μΈλ° λ‘κ·ΈμΈ μ°νκ° μ¬μ ν ν΅νλ€"
if echo "$ON_UNION" | grep -q 'S3cr3t-4dm1n-p4ss'; then fail "On μΈλ° UNION μ΄ μ¬μ ν ν΅νλ€"; fi
echo "$ON_NUM" | grep -q 'admin=1' || fail "μ«μ νλΌλ―Έν° λ°λ‘κ° μ¬νλμ§ μμλ€"
echo "$ON_GBK" | grep -q 'LOGIN OK' || fail "GBK μ°ν λ°λ‘κ° μ¬νλμ§ μμλ€"
docker rm -f l04-apm >/dev/null 2>&1 || true
echo "Off β λ‘κ·ΈμΈ μ°ν μ±κ³΅ Β· UNION μΌλ‘ νλ¬Έ λΉλ°λ²νΈ μ μΆ"
echo "On β λ‘κ·ΈμΈ μ°ν μ°¨λ¨ Β· UNION μ°¨λ¨"
echo "On β κ·Έλλ μ«μ νλΌλ―Έν°(idx=1 OR 1=1)μ GBK(0xbf27) λ ν΅κ³Ό : μμ ν λ°©μ΄κ° μλλ€"
echo
echo "β
PASS $EXPECT"./reproduce.sh
βΆπ μ½μ§ 3 β μ΄λ―Έμ§μ μ κ΅¬μ΄ νμ΄μ§ λλ¬Έμ μ¬νμ΄ κΉ¨μ‘λ€
gbk.php λ λ©μ μ΄λ―Έ λμ΄ λ€μ λ μ¬λΌμ docker cp λ‘ λ°μ΄ λ£μλ€. κ·Έ μνλ‘λ μ λμλ€.
κ·Έλ°λ° reproduce.sh λ 컨ν
μ΄λλ₯Ό μ§μ°κ³ μ΄λ―Έμ§μμ μλ‘ λ§λ λ€. μ 컨ν
μ΄λμλ κ·Έ νμΌμ΄ μλ€.
β FAIL β GBK μ°ν λ°λ‘κ° μ¬νλμ§ μμλ€μλμΌλ‘ νμΈν κ²κ³Ό μ€ν¬λ¦½νΈλ‘ μ¬νλλ κ²μ λ€λ₯΄λ€.
docker build λ₯Ό λ€μ λλ € www/ λ₯Ό μ΄λ―Έμ§μ κ΅½κ³ λμμΌ ν΅κ³Όνλ€.
"λ΄ νλ©΄μμλ λλλ°"κ° λ°±μ
ν΄λμμλ μ λλ μ νμ μΈ κ²½λ‘λ€.
π κ²°λ‘
λ΅μ magic_quotes_gpc λ€.
APM μ€νμμ μ ν리μΌμ΄μ
μ½λλ₯Ό μ κ³ μΉκ³ SQL Injection μ μ€μΌ μ μλ php.ini μ΅μ
μ
μ΄κ² νλλ€. λλ¨Έμ§ ν보λ€μ κ°κ° λ³μ μ€μΌ(register_globals) Β· νμΌ μ κ·Ό μ ν(safe_mode) Β·
μ 보 λ
ΈμΆ(display_errors) Β· μ격 νμΌ ν¬ν¨(allow_url_include) μ λ€λ£¨μ§, 쿼리 λ¬Έμμ΄μλ μλμ§ μλλ€.
λ΅μ΄ λ§λ€λ κ²κ³Ό κ·Έ λ°©μ΄κ° μΆ©λΆνλ€λ κ²μ λ€λ₯΄λ€.
λ©μμ νμΈν λλ‘ λ°μ΄ν κΈ°λ° μΈμ μ
λ κ°λ μ€μ λ‘ λ§νμ§λ§, μ«μ νλΌλ―Έν°μ
GBK λ¬Έμμ
μ°νλ μ΅μ
μ μΌ μνμμλ κ·Έλλ‘ ν΅νλ€. addslashes() λ κΈμ λ€ μ’
λ₯λ§ λ³΄λλ°
μΈμ μ
μ κ·Έ λ€ μ’
λ₯λ₯Ό μ μ¨λ μ±λ¦½νλ€.
μ΅μ μ 5.4 μμ μ¬λΌμ‘λ€.
μ μ μ€μ μΌλ‘ μ
λ ₯μ μ‘°μνλ©΄ μ ν리μΌμ΄μ
μ μκΈ° λ°μ΄ν°κ° μ΄μ€μΌμ΄νλ μνμΈμ§ μλμ§λ₯Ό μ μ μλ€.
κ·Έλμ κ·Έ μμ μ½λμλ get_magic_quotes_gpc() λ₯Ό λ¬Όμ΄λ³΄κ³ stripslashes() λ₯Ό λλ리λ
λ°©μ΄ μ½λκ° λλ € μμκ³ , κ·Έ μ½λκ° λ μλ‘μ΄ λ²κ·Έλ₯Ό λ§λ€μλ€. PHP λ 5.3 μμ deprecated,
5.4 μμ μ κ±°λ‘ μ 리νλ€.
μ§κΈ κ°μ μν©μ΄λΌλ©΄ 무μμ νλ.
쿼리λ ν리νμ΄λ μ€ν
μ΄νΈλ¨ΌνΈλ‘ λ§λ λ€(PDO μ prepare/execute, mysqli μ λ°μΈλ©).
κ°μ΄ λ¬Έμμ΄μ΄λ μ«μλ νλΌλ―Έν°λ‘ λμ΄κ°λ―λ‘ μμ λ λ°λ‘κ° λ λ€ μ±λ¦½νμ§ μλλ€.
λ¬Έμμ
μ μ°κ²° μ립 μ PDO DSN μ΄λ mysqli_set_charset() μΌλ‘ μ§μ νλ€ β
SET NAMES λ‘λ§ λ°κΎΈλ©΄ ν΄λΌμ΄μΈνΈ λΌμ΄λΈλ¬λ¦¬κ° λͺ¨λ₯Έ μ±λ‘ λ¨μ μ΄μ€μΌμ΄ν ν¨μκ° μλͺ»λ κ·μΉμ μ΄λ€.
μ΄ λ¬Έμ μ GBK λ°λ‘κ° λ°λ‘ κ·Έ μν©μ΄λ€.
λ¬Έμ μ체λ λ¨λ΅ νλμ§λ§, κ·Έ λ΅μ΄ μ λΉμμ μ λ΅μ΄μκ³ μ μ§κΈμ μ¬λΌμ‘λμ§κ° μ€μ λ κΈ΄ μ΄μΌκΈ°μλ€.
Comments
λκΈ
λκΈμ λ¨κΈ°λ €λ©΄ λ‘κ·ΈμΈμ΄ νμν΄μ. (λ€μ΄λ² Β· κ΅¬κΈ κ³μ )
λκΈ λΆλ¬μ€λ μ€β¦