输两个f1ag
还不够,看他的回复有个FLAG
,尝试加一个,成功得到flag
打开是一个上传界面,上传一个马试试,发现.php
被过滤不允许上传
$v1=0;$v2=0;$v3=0;
$a=(array)json_decode(@$_GET['iscc']);
if(is_array($a)){
is_numeric(@$a["bar1"])?die("nope"):NULL;
if(@$a["bar1"]){
($a["bar1"]>2016)?$v1=1:NULL;
}
if(is_array(@$a["bar2"])){
if(count($a["bar2"])!==5 OR !is_array($a["bar2"][0])) die("nope");
$pos = array_search("nudt", $a["bar2"]);
$pos===false?die("nope"):NULL;
foreach($a["bar2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
$v2=1;
}
}
$c=@$_GET['cat'];
$d=@$_GET['dog'];
if(@$c[1]){
if(!strcmp($c[1],$d) && $c[1]!==$d){
eregi("3|1|c",$d.$c[0])?die("nope"):NULL;
strpos(($c[0].$d), "isccctf2017")?$v3=1:NULL;
}
}
if($v1 && $v2 && $v3){
echo 12;
}
?>
可以根据他的代码直接构造
首先需要定义一个jason对象
,首先第一个为bar1
要求不是全数字且大于2016,简单,赋值为2017a
即可,这里用到了PHP弱类型的一个特性,当一个整形和一个其他类型行比较的时候,会先把其他类型intval再比。第二个是bar2
要求其是一个长度为5的数组,重点来了。
$pos = array_search("nudt", $a["bar2"]);
$pos===false?die("nope"):NULL;
foreach($a["bar2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
这两个其实是互相矛盾的,如何绕过?这时利用第一个"nudt"
字符串与0
弱类型比较相等,就可以绕过,方法:“bar2”:[[1],2,3,4,0]
后面array和string进行strcmp比较的时候会返回一个null,eregi直接用%00截断即可
最终构造
iscc={"bar1":"2017a","bar2":[[1],2,3,4,0]}&cat[1][]=1&dog=%00&cat[0]=0isccctf2017
打开,直接用御剑扫一下目录好了
抓包,结果测试的时候就得到flag,还以为是什么sql注入呢
先分析一下源码,发现没什么具体的漏洞,不过有个加密解密的函数,看看能不能逆出来
include 'hanshu.php';
if(isset($_GET['do']))
{
$do=$_GET['do'];
if($do==upload)
{
if(empty($_FILES))
{
$html1=<<
HTML1;
echo $html1;
}
else
{ $file=@file_get_contents($_FILES["filename"]["tmp_name"]);
if(empty($file))
{
die('do you upload a file?');
}
else
{
if((strpos($file,'')>-1)||(strpos($file,'?>')>-1)||(stripos($file,'php')>-1)||(stripos($file,')>-1))
{
die('you can\' upload this!');
}
else
{
$rand=mt_rand();
$path='/var/www/html/web-03/uploads/'.$rand.'.txt';
file_put_contents($path, $file);
echo 'your upload success!./uploads/'.$rand.'.txt';
}
}
}
}
elseif($do==rename)
{
if(isset($_GET['re']))
{
$re=$_GET['re'];
$re2=@unserialize(base64_decode(unKaIsA($re,6)));
if(is_array($re2))
{
if(count($re2)==2)
{
$rename='txt';
$rand=mt_rand();
$fp=fopen('./uploads/'.$rand.'.txt','w');
foreach($re2 as $key=>$value)
{
if($key==0)
{
$rename=$value;
}
else
{
if(file_exists('./uploads/'.$value.'.txt')&&is_numeric($value))
{
$file=file_get_contents('./uploads/'.$value.'.txt');
fwrite($fp,$file);
}
}
}
fclose($fp);
waf($rand,$rename);
rename('./uploads/'.$rand.'.txt','./uploads/'.$rand.'.'.$rename);
echo "you success rename!./uploads/$rand.$rename";
}
}
else
{
echo 'please not hack me!';
}
}
elseif(isset($_POST['filetype'])&&isset($_POST['filename']))
{
$filetype=$_POST['filetype'];
$filename=$_POST['filename'];
if((($filetype=='jpg')||($filetype=='png')||($filetype=='gif'))&&is_numeric($filename))
{
$re=KaIsA(base64_encode(serialize(array($filetype,$filename))),6);
header("Location:index.php?do=rename&re=$re");
exit();
}
else
{
echo 'you do something wrong';
}
}
else
{
$html2=<<
filetype: please input the your file's type
filename: please input your file's numeric name,like 12345678
HTML2;
echo $html2;
}
}
}
else
{
show_source(__FILE__);
}
?>
利用文中的机制本地测试一下,发现是大写字母+6
,小写字母-6
脚本
function KaIsA($text,$j)
{
echo $text."
";
for($i=0; $i < strlen($text); $i++)
{
$te = ord($text[$i]);
//echo $te."
";
if($te <=90 && $te >=65)
{
$te += $j;
if($te > 90 )
{
$te = $te - 26;
}
}
else if($te >=97 && $te <=122)
{
$te -= $j;
if($te < 97)
{
$te = $te + 26;
}
}
$text[$i] = chr($te);
}
echo $text."
";
return $text;
}
//$a[1]='728032523';
//$a[2]='53858205';
//$f1=base64_encode(serialize($a));
//KaIsA($f1,6);
$filename = '1909367105';
$filetype = 'php';
$re2 = KaIsA(base64_encode(serialize(array($filetype,$filename))),6);
?>
这样的话可以任意的更改后缀,好,现在就要开始上传一句话木马,由于有很强的绕过,但是代码中只要绕过key==0
就可以两次上传两个文件进行fwrite
拼接
定义一个数组,使第一位值空,然后后两位放两个文件,利用自己做的加密脚本加密,直接do=rename&re=字符串
拼接完以后改下后缀名,访问即可
猜测是sql注入的题,先测试一下
一开始测试id,结果发现消失,看来id是注入点
但之后无论怎么尝试都没见回显,一开始以为都被过滤,但后来经测试不是,猜测可能是'
被转义了
不过其实还有简单的,通过扫目录发现有个flag.php
有句提示
这都已经说明了hisisflag
是列名,flag
是表名
反正得到flag
flag:flag:{441b7fa1617307be9632263a4497871e}
直接username=' union select md5(1)#
password=1
然后验证码碰一个就好,出来flag
下载下来是一个.docx
文件,但通过分析,改成.zip
打开,在document.xml
中发现flag
差不多有105个点,可以是7的倍数,猜测是ascii
高位为1,低位为0,写出来,7位一组,直接转换
脚本
a = ['1100110',
'1101100',
'1100001',
'1100111',
'1111011',
'1010111',
'110000',
'1010111',
'101010',
'1100110',
'1110101',
'1101110',
'1101110',
'1111001',
'1111101']
flag = ''
for i in a:
#print i
flag += chr(int(i,2))
print flag
一开始是一张图片,用binwalk分析发现里面有一个zip压缩包,抠出来解压缩时发现需要密码
一开始真心不知道密码怎么解,想过爆破,不过后来仔细看题还是发现隐藏的hint,说是大于1000字,且落款为LiHua
,也就是密码大致为????LiHua
这样的话,尝试一下掩码爆破,直接出来
是一个数据包,分析一下,发现是用ftp下载文件
其中是一个key.txt的压缩包,解压缩是密文
里面还有公钥私钥
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0UN0A+70iM0VCJ1ni0n/U1BRj
0u8yMWH4Qi+xTbjHgbE7wOukOaO+2PyQXiqIzZnf5jCkJuVDYjALGcKrZM4OCQBB
d85B/LTc36XZ7JVfX5kGy5tIR3tquuPIVKNdAsHlSqh9S7YSS39RdnSa5rOUyGhr
LzxwzzM9IO4e+QQ+CQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQD0UN0A+70iM0VCJ1ni0n/U1BRj0u8yMWH4Qi+xTbjHgbE7wOuk
OaO+2PyQXiqIzZnf5jCkJuVDYjALGcKrZM4OCQBBd85B/LTc36XZ7JVfX5kGy5tI
R3tquuPIVKNdAsHlSqh9S7YSS39RdnSa5rOUyGhrLzxwzzM9IO4e+QQ+CQIDAQAB
AoGADiaw5mGubtCxbkeBOVYf+V/fXnjVSf76QbrzsD1kOooUjfV6sKR2C5Pd7S7H
H+1owENBBgEKvoBtb/cqA2tvU9vQ4l5TMBJcHv6LEcb9WPpnMxPV2GNjO+DTPGPy
Xnu1UZlZjwx+NaF5rESoSSVS2ZaaIixBs4RWRXk+lHEbTFECQQD6Rp6jMweRgPHO
pR3mgIK83zL+kzqYM5isIPv3DIC5JQN2kXqK73IDQCFVlfXnr9lAAVRzLDsAXLqv
le/o6yQLAkEA+edY+GERlLuD1t2k9Js0Dc7EwnLcxoFUE60ivj8Gf9jzLskGHxsv
0IV6J5OHwPh54kAxAnqCjSqNRAWGNzr+uwJBALYEjDUm1LdGrxXZ0jAkgHC6Z0zs
aK3uwHdXGcinqCp+t9EQpq3KzQF+L4AeKxRQONEq5m9I2LQ/vGocwrmD4dcCQQDb
rTyOinWz8upAFPKOe2hUwvA/pkzgyosoCMhDyI9kD0gmVlvlODbd7Jem9o8dWM97
zcXHUf41LbSkmN6U6m1FAkEAqmZbr35bPfkeoiikwNl6OVQytg12TZjw2vIbvfub
f9Rvti8Lh/tbrmhZroiz8/l3aAZmugI1NBcbeZR0gz8ggg==
-----END RSA PRIVATE KEY-----
-in指定被加密的文件,-inkey指定私钥文件,-out为解密后的文件。
下载下来居然有25张图片。。。猜测肯定是拼成一张二维码,就看怎么拼。。。试了试,直接 5∗5 排列发现有数字的地方涂黑就行
没有什么方法,只能利用表格默默的涂黑
这里有个坑就是他的二维码3个角需要根据二维码的特点调换下顺序
扫出来一堆字符
Vm0xd1NtUXlWa1pPVldoVFlUSlNjRlJVVGtOamJGWnlWMjFHVlUxV1ZqTldNakZIWVcxS1IxTnNhRmhoTVZweVdWUkdXbVZHWkhOWGJGcHBWa1paZWxaclpEUmhNVXBYVW14V2FHVnFRVGs9
一看就是base64解密,还好几层,解就行
flag:flag{y0ud1any1s1}
加密表:
1: < ZWAXJGDLUBVIQHKYPNTCRMOSFE <
2: < KPBELNACZDTRXMJQOYHGVSFUWI <
3: < BDMAIZVRNSJUWFHTEQGYXPLOCK <
4: < RPLNDVHGFCUKTEBSXQYIZMJWAO <
5: < IHFRLABEUOTSGJVDKCPMNZQWXY <
6: < AMKGHIWPNYCJBFZDRUSLOQXVET <
7: < GWTHSPYBXIZULVKMRAFDCEONJQ <
8: < NOZUTWDCVRJLXKISEFAPMYGHBQ <
9: < XPLTDSRFHENYVUBMCQWAOIKZGJ <
10: < UDNAJFBOWTGVRSCZQKELMXYIHP <
11: < MNBVCXZQWERTPOIUYALSKDJFHG <
12: < LVNCMXZPQOWEIURYTASBKJDFHG <
13: < JZQAWSXCDERFVBGTYHNUMKILOP <
密钥为:2,3,7,5,13,12,9,1,8,10,4,11,6
密文为:NFQKSEVOQOFNP
既然是车轮,看来需要轮换,一开始以为是将密文对应密钥位置进行替换,发现不对,查了查发现Jefferson wheel cipher(杰弗逊转轮加密器),差不多重新排一下序,并把密文转到第一个位置,发现flag:FIREINTHEHOLE
然后是base64加密,直接解码就好
flag:Flag:{Ly319.i5d1f*iCult!}
下载下来得到一串数字。。。感觉有点像16进制,但转码得不到什么实质性的东西,突然发现开头是504B
,是.zip
的头,估计就是文件的16进制
保存为zip格式,结果有密码,爆破吧
得到flag:daczcasdqwdcsdzasd
明显是猪圈密码,对应即可
flag:goodluck
得到两串字符
636A56355279427363446C4A49454A7154534230526D6843
56445A31614342354E326C4B4946467A5769426961453067
一看就很像16进制,转一下字符
cjV5RyBscDlJIEJqTSB0RmhC
VDZ1aCB5N2lKIFFzWiBiaE0g
似乎可以base64解密,试一下
r5yG lp9I BjM tFhB
T6uh y7iJ QsZ bhM
这里卡了有段时间,后来发现似乎跟键盘有关,围成圈
flag:TONGYUAN
通过提示,明显就是RSA的解密
首先看下下载的数据包文件,发现全是base64加密过的,解密发现有三个部分
SEQ
有顺序,那明显就是最后的字符顺序
DATA
明显是需要解密的密文
DATA
是发送给Bob的实际密文,使用Bob的公钥对DATA进行了加密。所以先使用factor-db并解出私钥来解密数据。
一开始不知道SIG
的作用,后来查资料发现是RSA的签名,利用Alice的公钥对数据进行一次签名验证
懒省事,直接写了一个大脚本
import base64
def iterative_egcd(a, b):
x,y, u,v = 0,1, 1,0
while a != 0:
q,r = b//a,b%a; m,n = x-u*q,y-v*q # use x//y for floor "floor division"
b,a, x,y, u,v = a,r, u,v, m,n
return b, x, y
def modinv(a, m):
g, x, y = iterative_egcd(a, m)
if g != 1:
return None
else:
return x % m
def base_convert():
f = open('C:\\Users\\lanlan\\Desktop\\out.txt','w+')
with open('C:\\Users\\lanlan\\Desktop\\1.txt') as lines:
for line in lines:
line = base64.b64decode(line)
f.write(line+'\n')
f.close()
def sort():
with open('C:\\Users\\lanlan\\Desktop\\out.txt') as lines:
line = lines.read()
f = open('C:\\Users\\lanlan\\Desktop\\outstream.txt','w+')
for i in range(0,34):
index = 0
for j in range(1,10):
b = line.find('SEQ = {};'.format(i),index)
if b == -1:
break
c = line.find('L;',b+55)
str = line[b:c+1]
f.write(str+'\n')
#print str
index = b+1
f.close()
def flag():
with open('C:\\Users\\lanlan\\Desktop\\outstream.txt') as lines:
B_p = 49662237675630289
B_q = 62515288803124247
B_s = (B_p-1)*(B_q-1)
B_n = 3104649130901425335933838103517383
A_p = 38456719616722997
A_q = 44106885765559411
A_n = 1696206139052948924304948333474767
e = 0x10001
d = modinv(e,B_s)
da = []
si = []
for line in lines:
begin_num = line.find('DATA')
end_num = line.find('L')
data = line[begin_num + 7: end_num]
#print data
data_c = int(data,16)
data_m = pow(data_c,d,B_n)
da.append(data_m)
#print data_m,
begin_n = line.find('SIG')
sig = line[begin_n + 6:-2]
#print sig
sig_c = int(sig,16)
sig_m = pow(sig_c,e,A_n)
si.append(sig_m)
#print sig_m,
#print da
#print si
flag = ''
for i in xrange(148):
#print i,da[i],si[i]
if da[i] == si[i]:
flag += chr(da[i])
print flag
if __name__ == '__main__':
base_convert()
sort()
flag()
flag:flag{n0th1ng_t0_533_h3r3_m0v3_0n}
得到一个hint和一个数据包
首先发开数据包发现是一个无线的协议,估计要破解wifi密码,利用aircrack-ng
工具
果真发现一个,首先利用hint:前四位是ISCC 后四位由大写字母和数字构成
生成一个字典
脚本
import itertools
import string
hex_chars = '0123456789'+string.ascii_uppercase
print hex_chars
wordlist = open('C:\\Users\\lanlan\\Desktop\\wordlist','a')
for words in itertools.product(hex_chars,repeat=4):
wordlist.write('ISCC' + ''.join(words) + '\n')
下载是一个加密脚本
function encrypt($data,$key)
{
$key = md5('ISCC');
$x = 0;
$len = strlen($data);
$klen = strlen($key);
for ($i=0; $i < $len; $i++) {
if ($x == $klen)
{
$x = 0;
}
$char .= $key[$x];
$x+=1;
}
for ($i=0; $i < $len; $i++) {
$str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
}
return base64_encode($str);
}
?>
解密脚本
function decrypt($str)
{
$key = md5("ISCC");
$str = base64_decode($str);
$len = strlen($str);
$x = 0;
for($i=0; $i < $len; $i++)
{
if($x == 32)
{
$x = 0;
}
$char .= $key[$x];
$x +=1;
}
for($i=0; $i < $len; $i++)
{
if((ord($str[$i])-ord($char[$i])) <= 0)
$data .= chr((ord($str[$i])+128-ord($char[$i])));
else
$data .= chr((ord($str[$i])-ord($char[$i])));
}
echo $data.'
';
}
$mi = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=';
decrypt($mi);
?>
python脚本方便
import base64
import string
def decrypt(str):
data = ""
char1 = ""
str = base64.b64decode(str)
#print str
key = '729623334f0aa2784a1599fd374c120d'
len1 = len(str)
klen = len(key)
x = 0
#print len1,klen
for i in range(0,len1):
if x == klen:
x = 0
char1 += key[x]
x = x+1
#print char1
for i in range(0,len1):
if (ord(str[i])-ord(char1[i])) <= 0:
data += chr((ord(str[i])+128-ord(char1[i])))
else:
data += chr((ord(str[i])-ord(char1[i])))
print data
if __name__ == '__main__':
a = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='
decrypt(a)
flag:Flag:{asdqwdfasfdawfefqwdqwdadwqadawd}
直接IDA反编译
主函数
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 result; // rax@3
__int64 v4; // rdx@7
char v5; // [sp+10h] [bp-10h]@4
__int64 v6; // [sp+18h] [bp-8h]@1
v6 = *MK_FP(__FS__, 40LL);
if ( a1 != 3 && (unsigned int)sub_400646((__int64)a2) )
{
puts("Keep thinking!");
result = 0LL;
}
else
{
printf("Please input your password(5 words):", a2, a2);
__isoc99_scanf("%5s", &v5);
if ( (unsigned int)sub_400755((__int64)&v5) == 1 )
{
printf("Good Job!\nThe password:%s", &v5);
result = 0LL;
}
else
{
puts("Wrong!");
result = 0LL;
}
}
v4 = *MK_FP(__FS__, 40LL) ^ v6;
return result;
}
首先是第一个函数的判定,必须返回0
signed __int64 __fastcall sub_400646(__int64 a1)
{
signed __int64 result; // rax@3
__int64 v2; // rcx@12
signed int i; // [sp+18h] [bp-48h]@1
signed int j; // [sp+1Ch] [bp-44h]@6
int v5; // [sp+20h] [bp-40h]@1
int v6; // [sp+24h] [bp-3Ch]@1
int v7; // [sp+28h] [bp-38h]@1
int v8; // [sp+2Ch] [bp-34h]@1
int v9; // [sp+30h] [bp-30h]@1
int v10; // [sp+40h] [bp-20h]@1
int v11; // [sp+44h] [bp-1Ch]@1
int v12; // [sp+48h] [bp-18h]@1
int v13; // [sp+4Ch] [bp-14h]@1
int v14; // [sp+50h] [bp-10h]@1
__int64 v15; // [sp+58h] [bp-8h]@1
v15 = *MK_FP(__FS__, 40LL);
puts(*(const char **)(a1 + 8));
v5 = 108;
v6 = 49;
v7 = 110;
v8 = 117;
v9 = 120;
v10 = 99;
v11 = 114;
v12 = 97;
v13 = 99;
v14 = 107;
for ( i = 0; i <= 4; ++i )
{
if ( *(_BYTE *)(*(_QWORD *)(a1 + 8) + i) != *(&v5 + i) )
{
result = 1LL;
goto LABEL_12;
}
}
for ( j = 0; j <= 4; ++j )
{
if ( *(_BYTE *)(*(_QWORD *)(a1 + 16) + j) != *(&v10 + j) )
{
result = 1LL;
goto LABEL_12;
}
}
result = 0LL;
LABEL_12:
v2 = *MK_FP(__FS__, 40LL) ^ v15;
return result;
}
很简单,10个字符意义对应即可
l1nux
,crack
然后第二个函数
__int64 __usercall sub_400755@(__int64 a1@)
{
__int64 result; // rax@6
if ( *(_BYTE *)a1 + *(_BYTE *)(a1 + 4) != 106 || *(_BYTE *)a1 != 73 )
{
result = 0LL;
}
else if ( *(_BYTE *)(a1 + 1) == 76 )
{
result = *(_BYTE *)(a1 + 2) + *(_BYTE *)(a1 + 3) == 137 && *(_BYTE *)(a1 + 3) == 70;
}
else
{
result = 0LL;
}
return result;
}
简单的逻辑
ILCF!
综上,flag:flag{l1nux_crack_ILCF!}
这题需要在gdb中动态调试看一下,直接看IDA的话,一些字符串看的不是很清楚,结合gdb 之后就很清楚了。 代码逻辑就是将已知的一个flag,进行一些移位变换,并将其中的_
改为 .
,然后就得到了最终真正的flag: flag{1t.is.5O.easy}
前面对注册表的操作都不用管,其实最关键的就是这个函数 sub_401210
,跟进去:
int __usercall sub_401210@(char *a1@)
{
wchar_t *v1; // eax@1
char *v2; // ecx@1
__int16 v3; // dx@2
wchar_t *v4; // eax@9
wchar_t *v5; // eax@11
unsigned int v6; // eax@11
wchar_t *v7; // eax@12
wchar_t *v8; // eax@13
int result; // eax@14
v1 = (wchar_t *)unknown_libname_1(0x32u);
v2 = a1;
// 这块代码没有什么意义,没有改变字符串
do
{
v3 = *(_WORD *)v2;
*(_WORD *)&v2[(char *)v1 ‐ a1] = *(_WORD *)v2;
v2 += 2;
}
while ( v3 );
result = 0;
// flag长为25位,并且形式是flag{xxx_x_xxxx_xxxxxxxx}
if ( wcslen(v1) == 25 && '{' == v1[4] && '_' == v1[8] && '_' == v1[10] && '_' == v1[15] && '}' == v1[24] )
{
wcstok(v1, L"{_}");
v4 = wcstok(0, L"{_}");
if ( *(_DWORD *)v4 == 6815860 && 52 == v4[4] )
{
v5 = wcstok(0, L"{_}");
// 数字型字符串转为整数
v6 = wtoi(v5);
if ( v6 >> 1 == v6 ‐ 2 ) // 3,4都可以,根据52 == v4[4]可以具体判断
{
v7 = wcstok(0, L"{_}");
if ( sub_401000(v7) )
{
v8 = wcstok(0, L"{_}");
if ( sub_401180(v8) )
result = 1;
}
}
}
}
return result;
}
首先确定flag的形式为 flag{xxx_x_xxxx_xxxxxxxx}
,然后根据wcstok将其分割为四个小部分,分别进行判断,最后还有一位是无法判断的,猜测吧,最后给出flag: flag{thx_4_your_register}