Team: Aurora
首先感谢L-CTF出题的师傅们为我们带来了一场精彩的CTF比赛,出题和运维的大佬们都辛苦了!
[TOC]
计算器算出来答案是-2
打开题目发现有点像2018Xctf-final决赛的一道题
首先这道题有一个回调函数,参数可控,session的内容也可控,同时扫描后台还发现了flag.php,如下
session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
$_SESSION['flag'] = $flag;
}
only localhost can get flag!
题目开始之后给了个hint:反序列化。
php中的session中的内容并不是放在内存中的,而是以文件的方式来存储的,存储方式就是由配置项session.save_handler来进行确定的,默认是以文件的方式存储。
存储的文件是以sess_sessionid来进行命名的,文件的内容就是session值的序列化之后的内容。
php的默认是php引擎,所以我们想要利用,需要先把引擎修改为php_serialize。
从flag.php可以看到,想要把flag写进session,需要本地访问,这里想到ssrf,而之前暨南大学招新赛的一道web题中提到了soap导致的ssrf,这个soap这个内置类刚好符合我们这道题
于是思路就有了,通过session反序列化攻击,触发ssrf去访问flag.php页面,把flag写进session里面。但是这里注意到,触发ssrf是如果不带上自己cookie去访问的话,是写不进自己session里面,这里需要利用到soap+crlf。
下面是攻击过程
然后通过变量覆盖,回调函数让soap去调用welcome_to_the_lctf2018方法,不存在,去调用_call方法,触发ssrf,写入session,最终得到flag
题目给了源码
<?php
$SECRET = `../read_secret`;
$SANDBOX = "../data/" . md5($SECRET. $_SERVER["REMOTE_ADDR"]);
$FILEBOX = "../file/" . md5("K0rz3n". $_SERVER["REMOTE_ADDR"]);
@mkdir($SANDBOX);
@mkdir($FILEBOX);
if (!isset($_COOKIE["session-data"])) {
$data = serialize(new User($SANDBOX));
$hmac = hash_hmac("md5", $data, $SECRET);
setcookie("session-data", sprintf("%s-----%s", $data, $hmac));
}
class User {
public $avatar;
function __construct($path) {
$this->avatar = $path;
}
}
class K0rz3n_secret_flag {
protected $file_path;
function __destruct(){
if(preg_match('/(log|etc|session|proc|read_secret|history|class)/i', $this->file_path)){
die("Sorry Sorry Sorry");
}
include_once($this->file_path);
}
}
function check_session() {
global $SECRET;
$data = $_COOKIE["session-data"];
list($data, $hmac) = explode("-----", $data, 2);
if (!isset($data, $hmac) || !is_string($data) || !is_string($hmac)){
die("Bye");
}
if ( !hash_equals(hash_hmac("md5", $data, $SECRET), $hmac) ){
die("Bye Bye");
}
$data = unserialize($data);
if ( !isset($data->avatar) ){
die("Bye Bye Bye");
}
return $data->avatar;
}
function upload($path) {
if(isset($_GET['url'])){
if(preg_match('/^(http|https).*/i', $_GET['url'])){
$data = file_get_contents($_GET["url"] . "/avatar.gif");
if (substr($data, 0, 6) !== "GIF89a"){
die("Fuck off");
}
file_put_contents($path . "/avatar.gif", $data);
die("Upload OK");
}else{
die("Hacker");
}
}else{
die("Miss the URL~~");
}
}
function show($path) {
if ( !is_dir($path) || !file_exists($path . "/avatar.gif")) {
$path = "/var/www";
}
header("Content-Type: image/gif");
die(file_get_contents($path . "/avatar.gif"));
}
function check($path){
if(isset($_GET['c'])){
if(preg_match('/^(ftp|php|zlib|data|glob|phar|ssh2|rar|ogg|expect)(.|\\s)*|(.|\\s)*(file)(.|\\s)*/i',$_GET['c'])){
die("Hacker Hacker Hacker");
}else{
$file_path = $_GET['c'];
list($width, $height, $type) = @getimagesize($file_path);
die("Width is :" . $width." px<br>" .
"Height is :" . $height." px<br>");
}
}else{
list($width, $height, $type) = @getimagesize($path."/avatar.gif");
die("Width is :" . $width." px<br>" .
"Height is :" . $height." px<br>");
}
}
function move($source_path,$dest_name){
global $FILEBOX;
$dest_path = $FILEBOX . "/" . $dest_name;
if(preg_match('/(log|etc|session|proc|root|secret|www|history|file|\.\.|ftp|php|phar|zlib|data|glob|ssh2|rar|ogg|expect|http|https)/i',$source_path)){
die("Hacker Hacker Hacker");
}else{
if(copy($source_path,$dest_path)){
die("Successful copy");
}else{
die("Copy failed");
}
}
}
$mode = $_GET["m"];
if ($mode == "upload"){
upload(check_session());
}
else if ($mode == "show"){
show(check_session());
}
else if ($mode == "check"){
check(check_session());
}
else if($mode == "move"){
move($_GET['source'],$_GET['dest']);
}
else{
highlight_file(__FILE__);
}
include("./comments.html");
这题应该是HITCON2017的一道题的改版,通过阅读代码,思路如下:
上传一个phar包改名为avatar.gif,然后上传到vps,upload上去,然后check的时候触发反序列化,然后包含进来,执行命令
参考:https://xz.aliyun.com/t/3190
这里触发反序列化是用到了getimagesize($file_path)这个函数。
然后利用类似
参考:https://blog.zsxsoft.com/post/38中提到的来绕过正则
最终得到flag
这道题是赛后半个小时后做出来的,都怪在线逆pyc辣鸡2333
打开得到题目源码
import re
import os
http_schema = re.compile(r"https?")
url_parser = re.compile(r"(\w+)://([\w\-@\.:]+)/?([\w/_\-@&\?\.=%()]+)?(#[\w\-@&_\?()/%]+)?")
base_dir = os.path.dirname(os.path.abspath(__file__))
sandbox_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "sandbox")
def parse_file(path):
filename = os.path.join(sandbox_dir, path)
if "./" in filename or ".." in filename:
return "invalid content in url"
if not filename.startswith(base_dir):
return "url have to start with %s" % base_dir
if filename.endswith("py") or "flag" in filename:
return "invalid content in filename"
if os.path.isdir(filename):
file_list = os.listdir(filename)
return ", ".join(file_list)
elif os.path.isfile(filename):
with open(filename, "rb") as f:
content = f.read()
return content
else:
return "can't find file"
def parse(url):
fragments = url_parser.findall(url)
if len(fragments) != 1 or len(fragments[0]) != 4:
return("invalid url")
schema = fragments[0][0]
host = fragments[0][1]
path = fragments[0][2]
if http_schema.match(schema):
return "It's a valid http url"
elif schema == "file":
if host != "sandbox":
return "wrong file path"
return parse_file(path)
else:
return "unknown schema"
@app.route('/sandbox')
def render_static():
url = request.args.get("url")
try:
if url is None or url == "":
content = "no url input"
else:
content = parse(url)
resp = make_response(content)
except Exception:
resp = make_response("url error")
resp.mimetype = "text/plain"
return resp
然后通过逆pyc文件得到main.py,hash.py,session.p,utils.py
源码后面给出
可以看到这里的hexdigest_group是一位一位加密得到的,所以我们只要分别得到a,d,m,i,n的hexdigest_group,这里通过不断清cookie得到即可伪造admin得到flag
a:b962d95efd252479
d:84407154c863ef36
m:e80346042c47531a
i:6e1beb0db216d969
n:b020cd1cf4031b57
MFSG22LO.b962d95efd25247984407154c863ef36e80346042c47531a6e1beb0db216d969b020cd1cf4031b57
main.py
# uncompyle6 version 3.2.3
# Python bytecode 3.7 (3394)
# Decompiled from: Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
# Embedded file name: main.py
# Size of source mod 2**32: 1135 bytes
from flask import Flask, escape, request, make_response, render_template
from session import *
from utils import *
from flag import FLAG
from parser import parse
app = Flask(__name__)
@app.route('/')
def index():
user = request.cookies.get('user', '')
try:
username = session_decode(user)
except Exception:
username = get_username()
content = escape(username)
else:
if username == 'admin':
content = escape(FLAG)
else:
content = escape(username)
resp = make_response(render_template('main.html', content=content))
return resp
@app.route('/sandbox')
def render_static():
if not check_token(request.args.get('token')):
resp = make_response('invalid request')
else:
url = request.args.get('url')
try:
if url is None or url == '':
content = 'no url input'
else:
content = parse(url)
resp = make_response(content)
except Exception:
resp = make_response('url error')
resp.mimetype = 'text/plain'
return resp
app.run(port=5000)
session.py
# uncompyle6 version 3.2.3
# Python bytecode 3.7 (3394)
# Decompiled from: Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
# Embedded file name: session.py
# Size of source mod 2**32: 718 bytes
import base64
from hash import MDA
from flag import seed
def encode(info):
return str(base64.b32encode(bytes(info, 'utf-8')), 'utf-8')
def decode(info):
return str(base64.b32decode(bytes(info, 'utf-8')), 'utf-8')
def hash_encode(info):
md = MDA('seed')
return md.grouping(info)
def hash_verify(hash_info, info):
return hash_encode(info) == hash_info
def session_encode(info):
return '%s.%s' % (encode(info), hash_encode(info))
def session_decode(info):
info_list = str.split(info, '.')
if len(info_list) != 2:
raise Exception('error info')
info_ = decode(info_list[0])
if not hash_verify(info_list[1], info_):
raise Exception('hash wrong')
return info_
print(session_encode('admin'))
hash.py
# uncompyle6 version 3.2.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
# Embedded file name: hash.py
# Size of source mod 2**32: 4512 bytes
__metaclass__ = type
import random, struct
def _bytelist2long(list):
imax = len(list) // 4
hl = [0] * imax
j = 0
i = 0
while i < imax:
b0 = ord(list[j])
b1 = ord(list[j + 1]) << 8
b2 = ord(list[j + 2]) << 16
b3 = ord(list[j + 3]) << 24
hl[i] = b0 | b1 | b2 | b3
i = i + 1
j = j + 4
return hl
def _rotateLeft(x, n):
return x << n | x >> 32 - n
def F(x, y, z):
return x & y | ~x & z
def G(x, y, z):
return x & z | y & ~z
def H(x, y, z):
return x ^ y ^ z
def I(x, y, z):
return y ^ (x | ~z)
def XX(func, a, b, c, d, x, s, ac):
res = 0
res = res + a + func(b, c, d)
res = res + x
res = res + ac
res = res & 65535
res = _rotateLeft(res, s)
res = res & 65535
res = res + b
return res & 65535
class MDA:
def __init__(self, seed='lctf2018'):
self.seed = seed
self.init()
def init(self):
self.length = 0
self.count = [0, 0]
self.input = []
random.seed(self.seed)
self.A = random.randint(3326, 27529)
self.B = random.randint(3326, 27529)
self.C = random.randint(3326, 27529)
self.D = random.randint(3326, 27529)
def _transform(self, inp):
a, b, c, d = A, B, C, D = (
self.A, self.B, self.C, self.D)
S11, S12, S13, S14 = (7, 12, 17, 22)
a = XX(F, a, b, c, d, inp[0], S11, 42104)
d = XX(F, d, a, b, c, inp[1], S12, 46934)
c = XX(F, c, d, a, b, inp[2], S13, 28891)
b = XX(F, b, c, d, a, inp[3], S14, 52974)
S21, S22, S23, S24 = (5, 9, 14, 20)
a = XX(G, a, b, c, d, inp[1], S21, 9570)
b = XX(G, b, c, d, a, inp[0], S24, 51114)
c = XX(G, c, d, a, b, inp[3], S23, 3463)
d = XX(G, d, a, b, c, inp[2], S22, 41976)
S31, S32, S33, S34 = (4, 11, 16, 23)
a = XX(H, a, b, c, d, inp[1], S31, 59972)
d = XX(H, d, a, b, c, inp[0], S32, 10234)
c = XX(H, c, d, a, b, inp[3], S33, 12421)
b = XX(H, b, c, d, a, inp[2], S34, 22117)
S41, S42, S43, S44 = (6, 10, 15, 21)
a = XX(I, a, b, c, d, inp[0], S41, 8772)
d = XX(I, d, a, b, c, inp[3], S42, 52370)
b = XX(I, b, c, d, a, inp[1], S44, 24017)
c = XX(I, c, d, a, b, inp[2], S43, 53947)
A = A + a & 32767
B = B + b & 32767
C = C + c & 32767
D = D + d & 32767
self.A, self.B, self.C, self.D = (
A, B, C, D)
def update(self, inBuf):
leninBuf = len(inBuf)
index = self.count[0] >> 3 & 15
self.count[0] = self.count[0] + (leninBuf << 3)
if self.count[0] < leninBuf << 3:
self.count[1] = self.count[1] + 1
self.count[1] = self.count[1] + (leninBuf >> 29)
partLen = 16 - index
if leninBuf >= partLen:
self.input[index:] = list(inBuf[:partLen])
self._transform(_bytelist2long(self.input))
i = partLen
while i + 15 < leninBuf:
self._transform(_bytelist2long(list(inBuf[i:i + 16])))
i = i + 16
else:
self.input = list(inBuf[i:leninBuf])
else:
i = 0
self.input = self.input + list(inBuf)
def insert(self, inBuf):
self.init()
self.update(inBuf)
def digest(self):
A = self.A
B = self.B
C = self.C
D = self.D
input = [] + self.input
count = [] + self.count
index = self.count[0] >> 3 & 15
if index < 8:
padLen = 8 - index
else:
padLen = 24 - index
padding = [''] + ['\x00'] * 15
self.update(padding[:padLen])
bits = _bytelist2long(self.input[:8]) + count
self._transform(bits)
digest = struct.pack('<hhhh', self.A, self.B, self.C, self.D)
self.A = A
self.B = B
self.C = C
self.D = D
self.input = input
self.count = count
return digest
def hexdigest(self):
return ''.join(['%02x' % ord(chr(c)) for c in self.digest()])
def grouping(self, inBufGroup):
hexdigest_group = ''
for inBuf in inBufGroup:
self.insert(inBuf)
hexdigest_group += self.hexdigest()
return hexdigest_group
util.py
# uncompyle6 version 3.2.3
# Python bytecode 3.7 (3394)
# Decompiled from: Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
# Embedded file name: utils.py
# Size of source mod 2**32: 1470 bytes
import random, string, base64, datetime
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
key = 'lctf2018lctf2018'
block_size = 16
def random_str(length=5):
random.seed(None)
return ''.join((random.choice(string.ascii_letters + string.digits) for _ in range(length)))
def get_username():
username = random_str(length=5)
if username != 'admin':
return username
else:
return get_username()
def check_token(token):
if token == '' or token is None:
return False
try:
token = str.replace(token, ' ', '+')
token = base64.b64decode(token)
cipher = AES.new(key, AES.MODE_ECB)
token = cipher.decrypt(token)
token = unpad(token, block_size)
token = str(token, 'utf-8')
except Exception as e:
try:
return False
finally:
e = None
del e
token = str.split(token, '@')
if len(token) != 4:
return False
try:
w = int(token[0])
h = int(token[1])
ua = token[2]
ts = datetime.datetime.fromtimestamp(int(token[3][:-3]))
except Exception as e:
try:
return False
finally:
e = None
del e
if w < 100 or h < 100:
return False
if 'urllib' in ua or 'requests' in ua or 'PhantomJS' in ua or 'Python' in ua or 'Scrapy' in ua or 'curl' in ua or 'Wget' in ua:
return False
now = datetime.datetime.now()
if ts < now + (datetime.timedelta(minutes=3)):
if ts > now - (datetime.timedelta(minutes=3)):
return True
return False
===================================
先是把输入的数据构建了一个二叉树,每一个节点是一个结构体
struct Bitree{
int data;
int subscript;//下标
Bitree *lchild;
Bitree *rchild;
};
构建的时候采取递归的方法,函数0040174C是构建二叉树的函数。比节点数据大的作为右孩子,小的作为左孩子,如果左(右)孩子存在了,则以此节点为参数继续执行0040174C函数,作为递归。
之后004017DD是二叉树的先序遍历函数,内存0040B610存放先序遍历的结果,内存0040B640存放对应数据的下标,至此初始化完成。
函数sub_401D6E为加密及校验函数。先把先序遍历转成二进制(每个字节的内容放进八个字节内,作为二进制表示),再对八个字节的二进制数进行一些swap和xor操作。大概可以猜到是DES,key是fa1conn
。des之后得到36字节的密文,作为一个6*6的矩阵和另一个6*6的常矩阵相乘,得到的结果再跟常量矩阵对比。由此,可以解出先序遍历的结果。
from numpy import*
from Crypto.Cipher import DES
A=[[0x17,0x41,0x18,0x4E,0x2B,0x38],[0x3B,0x43,0x15,0x2B,0x2D,0x4C],[0x17,0x36,0x4C,0x0C,0x41,0x2B],[0x59,0x28,0x20,0x43,0x49,0x39],[0x17,0x2D,0x1F,0x36,0x1F,0x34],[0x0D,0x18,0x36,0x41,0x22,0x18]]
mA=matrix(A)
B=[[0x0AA92,0x0C006,0x0A815,0x0C920,0x0D095,0x0CAD1],[0x7004,0x9B3C,0x68A1,0x0A2C1,0x8B5B,0x9EB5],[0x7E37,0x7AA2,0x4F95,0x0A344,0x82AC,0x8C00],[0x432B,0x71F7,0x732D,0x6E76,0x70A1,0x6F34],[0x0B465,0x0E401,0x0AF37,0x0DAD2,0x0DF89,0x0ECFA],[0x657D,0x6838,0x5FCE,0x977C,0x71F4,0x759E]]
mB=matrix(B)
mX=mB*mA.I
X=matrix.tolist(mX)
cipher=''
for i in range(6):
for j in range(6):
X[i][j]=int(round(X[i][j]))
cipher+=hex(X[i][j])[2:].zfill(2)
cipher+='733CF57C'
print(cipher)
cipher=cipher.decode('hex')
key='fa1conn\x00'
des = DES.new(key, DES.MODE_ECB)
plain=des.decrypt(cipher)
print(plain)
LC-+)=1234@AFETRS{the^VYXZfislrvxyz}
之后在00401ACC
比对了前半部分的下标,至此可以解出前半部分。
后面又有一个smc,把先序遍历数值做seed。接出来可以得到后半部分下标,就能得到完整flag了。
拿到手是一个接线图,一个hex文件,一个hex转成elf的.out,一个输出的内容图片
出题人已经告诉我们了单片机型好MSP430G2553。用ida打开lctf.out,在processor type中选择MSP430,就可以反汇编了。但是ida对msp430的分析优化不足,有些东西会缺失(也可能是hex转成的elf出了问题),只能连蒙带猜的做。
先去找一份msp430的指令集,对着指令集看汇编。
函数名和一些全局变量名都保留了,还是有突破口的,现在函数名内浏览一遍,发现了RC keygen main 等函数,大概猜到用的是RC4。先从main函数开始看。先call keygen函数,参数是全局变量key的地址(R12),这里应该是key初始化的函数。
分析这个keygen函数,先把一个0x28地址的内容放到R15,我猜这里是出了问题的,所以并不知道地址里放了什么东西,假设这个数据为i,后面几句就比较清晰了,key[4]=i*3, key[5]=i*2,key[6]=i&0x74,key[7]=i+0x50;这里只得到了后四位key,剩下的部分暂时不知道。
接下来回到main继续。在RC4_code的参数中有8,猜测是key的长度。找一下字符串,看到只有0123456789abcdefLCTF0000
这个字符串,最后四位都是0,感觉是把之前的四位填进去了,所以猜测key是LCTFxxxx。后四位都是从一个byte数据得到的,所以可以尝试爆key。脚本如下:
from Crypto.Cipher import ARC4
cipher = "2db7b1a0bda4772d11f04412e96e037c370be773cd982cb03bc1eade".decode("hex")
for i in xrange(0x100):
k4 = (i * 3) & 0xFF
k5 = (i * 2) & 0xFF
k6 = ((i & 0x74) * 2) & 0xFF
k7 = (i + 0x50) & 0xFF
key = "LCTF" + chr(k4) + chr(k5) + chr(k6) + chr(k7)
arc4 = ARC4.new(key)
plain = arc4.decrypt(cipher)
if(plain.find("CTF") != -1):
print(plain)
直接可以得到flag,也是比较幸运
Vm题
603080开始是三段bytecode
sub_4009D2函数分三次对三段bytecode操作,sub_401722和sub_4017C2是对寄存器的赋值与还原,中间的sub_401502函数是操作函数,详细分析bytecode,可以得出它的操作过程:
1.计算输入长度,校验是否等于0x1C
2.将输入的每一位ch进行如下操作:
ch=((ch*0x3f)+0x78)%0x80
3.与常量校验
把flag爆破出来就行了
a=[0x3E,0x1A,0x56,0x0D,0x52,0x13,0x58,0x5A,0x6E,0x5C,0x0F,0x5A,0x46,0x07,0x09,0x52,0x25,0x5C,0x4C,0x0A,0x0A,0x56,0x33,0x40,0x15,0x07,0x58,0x0F]
a.reverse()
b=[]
for i in range(28):
b.append(0)
for i in range(28):
for j in range(0x7F):
if ((j *0x3f)+0x7B)%0x80==a[i]:
b[i]=j
s=''
for i in range(28):
s+=chr(b[i])
print(s)
lctf{He11o_Virtual_Machine!}
from struct import unpack
f = open("./out.wav", "rb")
header = f.read(0xC)
fmt = f.read(0x18)
data = f.read(0x8)
buf = f.read()
f.close()
channel = 2
rate = 48000
length = 90000
key = bytearray("LCTF{LcTF_1s_S0Oo0Oo_c0o1_6uT_tH1S_iS_n0t_fL4g}")
ln = len(key)
tmp = bytearray(buf)
k = 0
n = 0
for i in xrange(length):
for j in xrange(channel):
m = key[n % ln]
tmp[k + 0] ^= m
tmp[k + 1] ^= m
n += m
k += 2
buf = str(tmp)
f = open("./dec.wav", "wb")
f.write(header + fmt + data + buf)
f.close()
解密之后用GoldWave
的x-y
模式就能看到flag.
LCTF{NOW_YOU_GOT_A_OSCILLOSCOPE_MEDIA_PLAYER}
改bin使之输出加密的结果.
0000559A22B498A0 -> 48 89 FE 48 C7 C0 0F 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
from pwn import *
context.log_level = "warn"
secret = "DQYHTONIJLYNDLA"
flag = ""
for i in xrange(len(secret)):
cc = " "
for ch in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
p = process("./enigma1")
p.sendline((flag + ch).ljust(15, "A"))
t = p.recvline(False)
p.close()
if(t.startswith(secret[:i + 1])):
cc = ch
break
flag += cc
print(flag)
LCTF{DOUBLEBUTTERFLY}
改bin使之输出加密的结果.
000055C60F62A568 -> 75 F8 90 90 90 90 90 90 90
000055C60F62A8A8 -> 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
from pwn import *
context.log_level = "warn"
secret = "IQURUEURYEU#WRTYIPUYRTI!WTYTE!WOR%Y$W#RPUEYQQ^EE"
flag = ""
for i in xrange(0, len(secret), 2):
cc = " "
for j in xrange(0x20, 0x7F):
ch = chr(j)
p = process("./maze1")
p.sendlineafter("Input your Flag:\n", (flag + ch).ljust(24, "A"))
t = p.recvline(False)
p.close()
if(t.startswith(secret[:i + 2])):
cc = ch
break
assert(cc != " ")
flag += cc
print(flag)
LCTF{Y0ur_fl4g_1s_wr0ng}
打开后是一个游戏,提示说赢了就能得到flag,直接在判定输赢的地方设断点,直接跳到赢就可以得到falg了
000000000040248F改成jmp
00000000004024B2nop掉
00000000004024C2nop掉
然后打开游戏按个空格就有flag了
好好学习,天天向上。