TOC

待整理

PHP

tool

讀 src 小筆記
PHP_FUNCTION(file_get_contents):  找 php function 定義

version feature

< 5.3.4

  • %00 截斷漏洞
    • aaa.php\x00.jpg 前後端: jpg; 解析: php

副檔名 extension

  • .php, .phpt, .phtml, .php[1-7]

config

  • location

    • phpinfo.php

      • Configuration File (php.ini) Path
      • Loaded Configuration File
      • Scan this dir for additional .ini files
    • common

      • /etc/php/php.ini
      • /etc/php5/php.ini
    • docker

      • /usr/local/etc/php
      • $PHP_INI_DIR
  • to config

    • ini_set
  • 配置模式:影響配置方式

  • 配置項總表

Syntax

Regex PCRE

PHP tags

  • config: short_open_tag
  • <?php;Standard tags
  • <?= = <?php echo:Short echo tag
  • <?: Short tag, default enabled

LFI

2021/12 多了一堆黑魔法

Check List

from easy to hard

  • wrapper & filename no length limit?
    • PHP_INCLUDE_TO_SHELL_CHAR_DICT
    • Side Channel to AFR
  • use official PHP docker image?

    /usr/local/lib/php/pearcmd.php

    • pearcmd.php LFI
  • cgi-bin?
    • /proc/self/environ & User-Agent
  • webserver log?

    /var/log/apache2/access.log
    /var/log/apache2/error.log

    • apache

    TODO

    • nginx
  • ssh?
    • /var/log/auth.log
  • directory readable?

    /tmp/PHP
    /var/tmp
    /var/lib/php/sessions
    /var/lib/php/
    /var/lib/php/sessions
    /tmp/
    /tmp/sessions/

    • enable POST upload?

      Linux .../php[a-zA-Z0-9]{6}
      Windows .../php[A-F0-9]{4}.tmp

      • file_uploads=On
      • phpinfo -> phpinfo race LFI
      • PHP 7/7.2 -> segment fault bruteforce LFI
    • enable session upload progress?

      .../upload_progress_<PHPSESSID>

      • session.upload_progress.enabled
      • session upload progress LFI
    • controllable & readable session file?

      .../sess_<PHPSESSID>

      • $_SESSION['xxxx'] = 'ooooo';
      • session LFI
  • Windows?
    • wildcard <<>"
    • UNC bypass allow_url_fopen=Off = 0 to RFI
  • wrapper & extension?
    • zip
    • phar deserialization attack
    • http(RFI)
  • PHP-FPM + Nginx with the same user & host?
    • Nginx Assistance
    • Nginx Fastcgi Tempfile

leave payload / controllable data

TOC

file upload temporary files

<form action="upload.php" method="post" enctype="multipart/form-data">
  Send these files:<br />
  <input name="userfile[]" type="file" /><br />
  <input name="userfile[]" type="file" /><br />
  <input type="submit" value="Send files" />
</form>

ref Gynvael Coldwind

多文件: https://www.php.net/manual/en/features.file-upload.multiple.php 可利用繞過檢測?

  • 處理完後自動刪除,需要 race 或阻止刪除發生
    • phpinfo race
    • php7/7.2 segment fault
      • php < 7.2: php://filter/string.strip_tags/resource=/etc/passwd
      • php7: php://filter/convert.quoted-printable-encode/resource=data://,%bfAAAAAAAAAAAAAAAAAAAAAAA%ff%ff%ff%ff%ff%ff%ff%ffAAAAAAAAAAAAAAAAAAAAAAAA
      • 觸發 segment fault 繞過刪除 temp file 步驟
      • 爆破 /tmp/php[a-zA-Z0-9]{6}
    • windows 通配符
      • C:\Windows\php<<

controllable session

# linux
/var/lib/php/sess_<PHPSESSID>
/var/lib/php/sessions/sess_<PHPSESSID>
/tmp/sess_<PHPSESSID>
/tmp/sessions/sess_<PHPSESSID>

# windows
c:\WINDOWS\TEMP\
c:\php\sessions\  
c:\php5\sessions\  
c:\php4\sessions\

session upload progress

.../upload_progress_<PHPSESSID>

  • POST with PHP_SESSION_UPLOAD_PROGRESS=xxxx
  • content in upload progress upload_progress_xxxx|.....

cgi-bin

  • php-cgi
  • /proc/self/environ & User-Agent

Webserver / ssh log

Nginx Assistance

Nginx Fastcgi Tempfile

Other

pearcmd.php

Include 技巧

phar

  • config
    • phar.readonly = Off
  • 改變附檔名,繞 suffix
    • 上傳限制 .png,LFI 會 append .php phar://aaa.png/bbb.php

偽協議

php://filter/[filters]/resource=[URI]
filters = ''|filter('|'filter)+
filter 會經過 URL decode,可以繞過 ./ 限制
convert.iconv.$in['.\']$out
root@a04f61d7ff35:/tmp# echo $'1\r\nT\r\n0ART' > /tmp/test && php -r 'echo file_get_contents("php://filter/dechunk/resource=/tmp/test")."\n";'
T
root@a04f61d7ff35:/tmp# echo $'aaaa' > /tmp/test && php -r 'echo file_get_contents("php://filter/dechunk/resource=/tmp/test")."\n";'

root@a04f61d7ff35:/tmp# echo $'zzzz' > /tmp/test && php -r 'echo file_get_contents("php://filter/dechunk/resource=/tmp/test")."\n";'
zzzz

路徑解析 path resolve

debug

  • show all error
    • php
    ​​ini_set('display_errors', 1);
    ​​ini_set('display_startup_errors', 1);
    ​​error_reporting(E_ALL);
    
    • .htaccess
    ​​php_flag display_startup_errors on
    ​​php_flag display_errors on
    
    • .ini
    ​​display_errors = on
    

php magic hash number

  • https://github.com/spaze/hashes
  • md5
    • p == hash(p):0e215962017=>0e291242476940776845150308577824
    • hash(p) == 0:12832323351hello=>0e107303994101791601610489605716
    • hash(num) == 0: 240610708=>0e462097431906509019562988736854
    • hash(UPPER) == 0: QLTHNDT=>0e405967825401955372549139051580
    • .V;m=*]b?-=>00e45653718969294213009554265803

functions

require_once

uniqid

Returns timestamp based unique identifier as a string.

  • 可以被爆破出來

move_uploaded_file

make sure that the file name not bigger than 250 characters.

  • filename 會失敗
  • from 非 uploaded file 會失敗
  • 通常 > 255 就會失敗 ref

parse_url

usage
print(parse_url('scheme://user:pass@host/path?query#fragment'))

(
    [scheme] => scheme
    [host] => host
    [user] => user
    [pass] => pass
    [path] => /path
    [query] => query
    [fragment] => fragment
)
  • parse_url 不會做 urldecode,但是一些協議在 file_get_contents 等等會先做 urldecode,因此可以繞過限制
// kaibro Tricky Web
> $file = 'data:,%2f%2f/';
> print_r(parse_url($file));
Array
(
    [scheme] => data
    [path] => ,%2f%2f/
)
> echo file_get_contents($file);
///
  • parse 邏輯
    • php_url_parse_ex2
    • scheme = 1*[ lowalpha | digit | "+" | "-" | "." ]
    • 先解析 fragement 後才是 query

filter_var

  • 過長截斷繞過https://pwning.systems/posts/php_filter_var_shenanigans/

sha1

  • 7.4.0 - 7.4.30: 非字串會跳 warning 回傳 null
  • 8: 修補跳 Fatal Error

preg_match

  • 使用 PCRE

  • 7.4.0 - 7.4.30: 第一或第二參數非字串回傳 false

    • 結合 first class callable $a=['A','m'];if(!preg_match('/a-z/i',$a))$a();
  • 8.0.1 - 8.0.21, 8.1.0 - 8.1.8: 第一或第二參數非字串跳 error

  • regex 跳脫錯誤

    • wrong var_dump(preg_match("/\\|a/", "\\"));
    • correct var_dump(preg_match("/\\\\|a/", "\\"));
  • 回溯上限是 1,000,000

// by Kaibro
<?php
if(preg_match('/UNION.+?SELECT/is', 'UNION/*'.str_repeat("a",1000000)."*/SELECT")) {
 die('Failed');
}
die('SQL Injection');

mysql_real_escape_string

strcmp

  • 相等回傳 0
  • 傳入非字串回傳 null, var_dump(strcmp([],'secret') == strcmp('secret','secret'));
  • php 8 修復ㄌ

__HALT_COMPILER()

  • 只能在最外層呼叫,後面內容不解析
  • 類似註釋效果?

cgi mode

  • PATH_INFO, SCRIPT_NAME 解析問題
    • nginx
    • /aaa.jpg/bbb.php
      • 不存在 bbb.php 的話會查看 aaa.jpg
      • cgi.fix_pathinfo=0 修補

Windows

Windows FindFirstFile API 正規化

serialize/unserialize

ref

https://www.anquanke.com/post/id/251366

  • 類名 case insensitive
    ​​​​<?php
    ​​​​class B{
    ​​​​}
    ​​​​$a = new b();
    ​​​​$a = unserialize('O:1:"b":0:{}');
    ​​​​print_r($a);
    ​​​​//
    ​​​​B Object
    ​​​​(
    ​​​​)
    
  • serialize, unserialze
  • phpggc
  • fast destruct
    • 構造有問題的序列化字串,讓他解析失敗後提前觸發 object __destruct

    如果 parent object 有 __wakeup 的話順序不會被打亂]

    code
    ​​​​class A{
    ​​​​  function __destruct()
    ​​​​  {
    ​​​​    echo "A::destruct\n";
    ​​​​  }
    ​​​​} 
    ​​​​class B{
    ​​​​  function __wakeup()
    ​​​​  {
    ​​​​    echo "B::wakeup\n";
    ​​​​  }
    ​​​​  function __destruct()
    ​​​​  {
    ​​​​    echo "B::destruct\n";
    ​​​​  }
    ​​​​} 
    
    ​​​​// 正常
    ​​​​$a = unserialize('O:1:"A":1:{s:1:"b";O:1:"B":0:{}}');
    ​​​​//
    ​​​​B::wakeup
    ​​​​A::destruct
    ​​​​B::destruct
    
    ​​​​// fast destruct
    ​​​​$a = unserialize('O:1:"A":2:{s:1:"b";O:1:"B":0:{}}');
    ​​​​//
    ​​​​PHP Notice:  unserialize(): Unexpected end of serialized data in /home/eethan1/Projects/popaeg/bbb.php on line 19
    
    ​​​​Notice: unserialize(): Unexpected end of serialized data in /home/eethan1/Projects/popaeg/bbb.php on line 19
    ​​​​PHP Notice:  unserialize(): Error at offset 31 of 32 bytes in /home/eethan1/Projects/popaeg/bbb.php on line 19
    
    ​​​​Notice: unserialize(): Error at offset 31 of 32 bytes in /home/eethan1/Projects/popaeg/bbb.php on line 19
    ​​​​A::destruct
    ​​​​B::wakeup
    ​​​​B::destruct
    ​​​​// 如果 A 有定義 __wakeup A::destruct 不會被觸發
    ​​​​PHP Notice:  unserialize(): Unexpected end of serialized data in /home/eethan1/Projects/popaeg/bbb.php on line 23
    
    ​​​​Notice: unserialize(): Unexpected end of serialized data in /home/eethan1/Projects/popaeg/bbb.php on line 23
    ​​​​PHP Notice:  unserialize(): Error at offset 31 of 32 bytes in /home/eethan1/Projects/popaeg/bbb.php on line 23
    
    ​​​​Notice: unserialize(): Error at offset 31 of 32 bytes in /home/eethan1/Projects/popaeg/bbb.php on line 23
    ​​​​B::wakeup
    ​​​​B::destruct
    
  • __PHP_Incomplete_Class
    • __PHP_Incomplete_Class_Name 帶要找的類名
    • 可以加其他 property
    • 序列化時若無 __PHP_Incomplete_Class_Name 則 property 會被清空
    ​​​​<?php
    ​​​​$a = unserialize('O:22:"__PHP_Incomplete_Class":1:{s:1:"b";s:3:"cmd";}');
    ​​​​print_r($a);
    ​​​​print_r(serialize($a));
    ​​​​//
    ​​​​php__PHP_Incomplete_Class Object
    ​​​​(
    ​​​​    [b] => cmd
    ​​​​)
    ​​​​O:22:"__PHP_Incomplete_Class":0:{}
    
    • 可以繞檢測(?
  • 不只 magic method, interface 也是 gadget

TODO

  • off by one error

kaibro