吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6070|回复: 21
收起左侧

[CTF] 2021GFCTF RE部分WP

[复制链接]
zsky 发表于 2021-11-25 17:38
本帖最后由 zsky 于 2021-11-25 19:29 编辑

2021GFCTF  RE_WP

wordy

去除花指令

image-20211125095945784.png

addr =0X556AE377FD56
end = 0x0556AE377FE40
flag = ""
for i in range(addr, end, 13):
    c = get_bytes(i+4, 1)[0]
    flag+=chr(c)

print(flag)
# GFCTF{u_are2wordy}

BabyReverse

IDA打开,去除所有的花指令

image-20211125100636917.png

直接看下面对flag如何加密的,进入sub_412E10, 发现是SM4加密

image-20211125100743339.png

而传入的第二个参数是key,即byte_4409c0是key,回到main函数再往上看,发现前面有一个对byte_4409c0类似RC4加密的操作,

byte_4409C0进行交叉引用

image-20211125100949459.png

image-20211125101052255.png

于是下断点调试来获取key,发现不行,猜测前面是反调试,从main函数头部下断点调试

image-20211125101538394.png

最终定位到这个函数

image-20211125101557018.png

采用的是self_mapping技术实现反调试,本质是创建secion的时候设置SEC_NO_CHANGE,映射后不能改变节区属性

Self-Remapping-Code

关于这个技术,可以参考下这位大佬的笔记 https://jev0n.com/2021/09/23/Self-Remapping.html

我们直接将call sub_411CE0 的地方nop掉,手动的把byte_4409c0的地方加1

a = [  0x07, 0xB8, 0x0D, 0x24, 0xB1, 0x0C, 0x2D, 0xC7, 0x28, 0x2D, 
  0xC3, 0x61, 0x66, 0x4F, 0x72, 0x13]

addr = 0x04409C0
for i in range(16):
    patch_byte(addr+i, a[i]+1)

print("OK")

运行起来

image-20211125102324766.png

得到key为 GF?->GirlFriend?

提取密文

0D 40 3B 87 A5 66 DA 74 92 7F BB E1 B8 CD EB BC 59 45 1B C0 38 99 AA 22 AA 3F 9D 21 07 4E 81 1F

SM4在线解密

image-20211125102923390.png

2e69df5961f20aee0897cf1905156344, 最终得到flag为 GFCTF{2e69df5961f20aee0897cf1905156344}

re_EasyRE_0x00

IDA打开分析,最关键的是sub_100016A0函数

image-20211125151517064.png

image-20211125151806585.png

经过分析,发现sub_10001180是解密login.key文件,生成的数据放到V13里面

然后下面这个地方是将V13处的数据与生成的一些数据进行对比,猜测是机器码的验证

image-20211125151922458.png

这是V13处的数据

11 55 66 55 0D 50 51 0C FF 01 80 12 CE A9 08 75 73 65 72 32 33 33 33

最后8个字符是user2333

将对比的数据也提取出来, 然后结合题目,用户名用admin6677登录,长度是9,整理得

11 55 66 55 98 FA 9B 59 6F F6 14 8F E9 DA 09 61 64 6D 69 6E 36 36 37 37

我们写脚本,每次运行到对比数据的时候就把v13的数据给他替换掉

data = [0x11, 0x55, 0x66, 0x55, 0x98, 0xFA, 0x9B, 0x59, 0x6F, 0xF6, 0x14, 0x8F, 0xE9, 0xDA, 0x09, 0x61, 0x64, 0x6D, 0x69, 0x6E, 0x36, 0x36, 0x37, 0x37]
addr = 0x004CB348  # v13的地址
for i in range(len(data)):
    patch_byte(addr+i, data[i])
print("OK")

然后绕过机器码验证,往下走,来到sub_10001610

image-20211125152844760.png

可以发现,这个地方肯定是与服务器通信了,我们直接运行,直接Wireshark抓包

提取数据

---> 11 55 66 55 1a 27 00 00 00 00

<--- 11 55 66 55 66 27 00 00 0f 00 f3 46 8a be 81 62 ed 36 d5 df 28 dc 04 8a fd

---> 11 55 66 55 1a 27 01 00 40 00 0e a2 60 19 1f df 39 0d bc 62 48 57 5a 11 87 78 69 11 03 76 4b f9 2c 1f 35 fd ff 4a b8 d8 63 8f b6 b1 f0 cd d3 90 2d 27 05 b7 1e 01 22 74 91 1a a4 53 df 1d f4 69 7d 3e 29 bd d3 30 da 94 a3 03

<--- 11 55 66 55 66 27 01 00 48 00 84 cb 11 ef 71 51 30 0b b3 d8 c1 22 ac c4 ca f1 29 12 cf 79 f5 36 5f 5a 5e a8 f5 fa 62 3c e8 32 69 d6 a1 54 eb 1b 06 06 b0 68 20 5a 62 ea 48 ec 8a 3d 5c 40 d0 a8 03 94 6a 2e b7 f0 e4 33 aa a0 e3 f2 da f8 a9 cf 5d 92 

重新调试,接着刚才的位置往下分析,看到了RC4的初始化及加密

image-20211125155302278.png

image-20211125155318573.png

猜测是刚开始,服务器端返回RC4的key,然后后面全部使用RC4加密方式进行加密

image-20211125155723782.png

根据sub_10001350这个函数可以猜测出数据包的格式, 拿上面服务器返回的key举例子

11 55 66 55 //标志
66 27       //版本
00 00       //命令
0f 00       //后面数据的长度
f3 46 8a be 81 62 ed 36 d5 df 28 dc 04 8a fd  //数据,当命令为0的时候,是RC4的key,命令为1和2的时候,是RC4加密的数据

写脚本验证RC4加密

from Crypto.Cipher import ARC4 as rc4cipher
import binascii

def rc4_algorithm(encrypt_or_decrypt, data, key1):
    if encrypt_or_decrypt == "enc":
        key = key1
        enc = rc4cipher.new(key)
        res = enc.encrypt(data)
        return res
    elif encrypt_or_decrypt == "dec":
        key = key1
        enc = rc4cipher.new(key)
        res = enc.decrypt(data)
        return res

key = binascii.unhexlify("f3468abe8162ed36d5df28dc048afd")
data1 = binascii.unhexlify(
    "0ea260191fdf390dbc6248575a118778691103764bf92c1f35fdff4ab8d8638fb6b1f0cdd3902d2705b71e012274911aa453df1df4697d3e29bdd330da94a303")
m1 = rc4_algorithm("dec", data1, key)

data2 = binascii.unhexlify(
    "84cb11ef7151300bb3d8c122acc4caf12912cf79f5365f5a5ea8f5fa623ce83269d6a154eb1b0606b068205a62ea48ec8a3d5c40d0a803946a2eb7f0e433aaa0e3f2daf8a9cf5d92")
m2 = rc4_algorithm("dec", data2, key)

print(m1)
print(m2)
# b'\x8ayqv,\x8eYjj\xdb\xfa\x10\xd6\xa0=\xed!w\xa9/\xdd\xa3\x1a \x05!+\xbd\xd0\xa7\xe7\xd4\xba\t%\xb9N\xeeYR\xdc\xb0Pfq\xae\xe9\xc7\x1eB\xa3\x0eA\xb3\x08\xcf1\xb3\x12\xa5L\xd4`\xcc'
# b'\x00\x10\x00\x80B\x00Please update client!\r\nClient version=10010, Server version=10086\x00'

image-20211125160348983.png

结合login.key,发现当命令为1的时候,向服务器发送的是login.key的数据,然后服务器返回信息

所以现在需要构造 真正的login.key(11 55 66 55 98 FA 9B 59 6F F6 14 8F E9 DA 09 61 64 6D 69 6E 36 36 37 37)

加密后的数据

sub_10001180是解密函数,进去分析,发现是RSA的PKCS#1加密

image-20211125160757257.png

根据这个结构找到e和n

image-20211125161211503.png

image-20211125161253534.png

提取出来

e: 65537
n: 0xd928b8efe000f72db5bda67a9aa0740defb555b2603736eecd6d01f38ef2fc79
分解得到p, q
p = 322922590106035145437937724697895880569
q = 304171468404401467258708275665013611777

利用rsatool.py生成private.pem

 python rsatool.py -e 65537 -p 322922590106035145437937724697895880569 -q 304171468404401467258708275665013611777 -o private.pem

利用在线解密网站测试 https://the-x.cn/cryptography/Rsa.aspx

image-20211125162250321.png

发现解密成功,将构造好的数据进行加密,

image-20211125162342644.png

对于PKCS#1的填充方式可以参考下面2篇文章

https://www.cloudcared.cn/3155.html

https://www.cnblogs.com/feng9exe/p/8075447.html

然后写程序与服务器交互,发现服务器返回命令为2的验证码问题

Question(Send result in uint32_t format, 1 second!): 9540808 * 32 + 509 * 859 = ?

然后利用eval计算数值,构造,返回给服务器,即可得到flag,完整的exp如下

import socket
from Crypto.Cipher import ARC4 as rc4cipher
import re
import struct

login_key = [0x5D, 0x98, 0xEE, 0x8B, 0x68, 0x86, 0x2F, 0x56, 0xBA, 0xA1, 0x27, 0x2A, 0x68, 0x8B, 0x19, 0x31, 0x37, 0xC1, 0x2B, 0x1A, 0x80, 0x5F, 0xAB, 0x8C, 0xE0, 0xE6, 0x81, 0xDF, 0x05, 0xC6, 0xB1,
             0x2F, 0x0E, 0x59, 0xC8, 0x45, 0x8A, 0x7D, 0x83, 0x35, 0x5F, 0x02, 0x05, 0x10, 0x8A, 0x35, 0x6D, 0x0C, 0xE8, 0x3C, 0x9C, 0x15, 0xD7, 0xDA, 0xF0, 0x96, 0x6D, 0x2E, 0x77, 0xEC, 0x78, 0x3B, 0x83, 0xB2]

def rc4_algorithm(encrypt_or_decrypt, data, key1):
    if encrypt_or_decrypt == "enc":
        key = key1
        enc = rc4cipher.new(key)
        res = enc.encrypt(data)
        return res
    elif encrypt_or_decrypt == "dec":
        key = key1
        enc = rc4cipher.new(key)
        res = enc.decrypt(data)
        return res

def get_data(_cmd, _len, _data, _key):
    sig = [0x11, 0x55, 0x66, 0x55]      # 签名
    banben = [0x66, 0x27]               # 版本
    cmd_list = [_cmd, 0x00]             # 命令
    data_len_list = [_len, 0x00]        # 数据长度
    if _len != 0:
        return bytes(sig + banben + cmd_list + data_len_list) + rc4_algorithm('enc', bytes(_data), _key)
    return bytes(sig + banben + cmd_list + data_len_list)

def get_captcha(_captcha_str):
    m = re.search(
        r"Question\(Send result in uint32_t format, 1 second!\): (.*?) = ", _captcha_str)
    c = eval(m.group(1))
    return struct.pack("I", c)

if __name__ == '__main__':
    address = ('119.27.179.145', 10086)

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(address)

    s.send(get_data(0, 0, [], None))
    data = s.recv(1024)
    rc4_key = data[10:]                 # 获取RC4密钥

    s.send(get_data(1, 0x40, login_key, rc4_key))
    data = s.recv(1024)
    captcha_str = rc4_algorithm("dec", data[10:], rc4_key).decode()
    captcha = get_captcha(captcha_str)        # 计算得到验证码
    print(f"Captcha: {captcha}")

    # 向服务器返回验证码
    send_data = get_data(2, len(captcha), list(captcha), rc4_key)
    s.send(send_data)
    data = s.recv(1024)
    m = rc4_algorithm("dec", data[10:], rc4_key)
    print(m)
    s.close()

    # Captcha: b'\xc84\x06\x03'
    # b'\x00\x10\x00\x805\x00flag_0x00 = \x00GFCTF{e8e9071b7a70770bec1f6415c4ed4c1d}\x00'

得到flag为 GFCTF{e8e9071b7a70770bec1f6415c4ed4c1d}

这个Easy_RE在番外篇结束第1天捣鼓出来了,有点可惜,一直卡在找N和那个RSA解密了,一直在用常规的pow(c,d,n)解,后来才发现,RSA加密也得符合一定的标准,填充数据什么的,这里就是用了最普通的PKCS#1,还是学到了很多东西的,继续加油。

免费评分

参与人数 10威望 +2 吾爱币 +109 热心值 +10 收起 理由
gaosld + 1 + 1 谢谢@Thanks!
HAIANAWEI + 1 谢谢@Thanks!
ZJevon + 2 + 1 师傅太强了
fankaiqiang + 1 + 1 我很赞同!
zhangxiaosi78 + 1 + 1 谢谢@Thanks!
努力加载中 + 1 + 1 热心回复!
qiwenchun + 1 + 1 谢谢@Thanks!
笙若 + 1 + 1 谢谢@Thanks!
Hotspur + 1 + 1 谢谢@Thanks!
Hmily + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

ZJevon 发表于 2021-11-26 20:09
chenjingyes 发表于 2021-11-26 16:52
楼主不把题目附件传上?

https://jev0n.lanzoui.com/ibhzswxjbza  可以看这里,同时也欢迎师傅们参加明年的GFCTF
chenjingyes 发表于 2021-11-29 16:36
ZJevon 发表于 2021-11-26 20:09
https://jev0n.lanzoui.com/ibhzswxjbza  可以看这里,同时也欢迎师傅们参加明年的GFCTF

好的 哈哈
Hmily 发表于 2021-11-25 18:16
 楼主| zsky 发表于 2021-11-25 18:46
Hmily 发表于 2021-11-25 18:16
最后多了两张图没有插入到正文?

好的,我修正下
52wxl 发表于 2021-11-25 19:04
大佬,你真厉害
rzxcs 发表于 2021-11-25 23:57
高手在民间。
JPK 发表于 2021-11-26 09:08
不错哦,get到了
lsjhwei 发表于 2021-11-26 10:07
谢谢分享
liujiata 发表于 2021-11-26 14:33
分析的很不错。值得学习。
chenjingyes 发表于 2021-11-26 16:52
楼主不把题目附件传上?
 楼主| zsky 发表于 2021-11-26 17:35
chenjingyes 发表于 2021-11-26 16:52
楼主不把题目附件传上?

这个的题目附件我应该是没备份,全是我patch后的,之后的比赛我记得备份
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 12:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表