最近玩了一下owasp,碰到一个题目之前在ctf中也出过类似的题.做个记录有备无患.
题目第一步是要找到优惠码
看下源码在输入的地方有个验证优惠码的地方.接着找到这个验证函数所在的js文件.
var coupons = ["nvojubmq",
"emph",
"sfwmjt",
"faopsc",
"fopttfsq",
"pxuttfsq"];
function isValidCoupon(coupon) {
coupon = coupon.toUpperCase();
for(var i=0; i<coupons.length; i++) { // coupons.length = 6
decrypted = decrypt(coupons[i]);
if(coupon == decrypted){
ajaxFunction(coupon);
return true;
}
}
return false;
}
function decrypt(code){
code = code.toUpperCase();
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
caesar = '';
for (i = code.length ;i >= 0;i--){
for (j = 0;j<alpha.length;j++){
if(code.charAt(i) == alpha.charAt(j)){
caesar = caesar + alpha.charAt((j+(alpha.length-1))%alpha.length);
}
}
}
return caesar;
}
function ajaxFunction(coupon)
{
var xmlHttp;
try
{
// Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
alert("Your browser does not support AJAX!");
return false;
}
}
}
xmlHttp.onreadystatechange=function()
{
if(xmlHttp.readyState==4)
{
document.form.GRANDTOT.value = calcTot(document.form.SUBTOT.value , xmlHttp.responseText);
}
}
xmlHttp.open("GET","lessons/Ajax/clientSideValidation.jsp?coupon=" + coupon,true);
xmlHttp.send(null);
}
function updateTotals(){
f = document.form;
f.TOT1.value = calcTot(f.PRC1.value , f.QTY1.value);
f.TOT2.value = calcTot(f.PRC2.value , f.QTY2.value);
f.TOT3.value = calcTot(f.PRC3.value , f.QTY3.value);
f.TOT4.value = calcTot(f.PRC4.value , f.QTY4.value);
f.SUBTOT.value = formatCurrency(unFormat(f.TOT1.value)
+ unFormat(f.TOT2.value)
+ unFormat(f.TOT3.value)
+ unFormat(f.TOT4.value));
f.GRANDTOT.value = f.SUBTOT.value;
isValidCoupon(f.field1.value);
}
function unFormat(price){
price = parseFloat(unFormatCurrency(price));
if(isNaN(price))
price = 0;
return price;
}
function calcTot( price, qty){
price = unFormatCurrency(price);
return formatCurrency(price*qty);
}
function unFormatCurrency(price){
price = price.toString().replace(/\$|\,/g,'');
return price;
}
function formatCurrency(num) {
num = num.toString().replace(/\$|\,/g,'');
if(isNaN(num))
num = "0";
sign = (num == (num = Math.abs(num)));
num = Math.floor(num*100+0.50000000001);
cents = num%100;
num = Math.floor(num/100).toString();
if(cents<10)
cents = "0" + cents;
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+','+
num.substring(num.length-(4*i+3));
return (((sign)?'':'-') + '$' + num + '.' + cents);
}
可以看到在这个地方函数isValidCoupon() 的参数coupon就是输入的优惠码,然后他是将coupon转成大写然后跟coupons里的coupon(这个在js的最开始就有)经过decrypt后的结果进行比较.
function isValidCoupon(coupon) {
coupon = coupon.toUpperCase();
for(var i=0; i<coupons.length; i++) { // coupons.length = 6
decrypted = decrypt(coupons[i]);
if(coupon == decrypted){
ajaxFunction(coupon);
return true;
}
}
return false;
}
然后看decrypt()函数
function decrypt(code){
code = code.toUpperCase();
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
caesar = '';
for (i = code.length ;i >= 0;i--){
for (j = 0;j<alpha.length;j++){
if(code.charAt(i) == alpha.charAt(j)){
caesar = caesar + alpha.charAt((j+(alpha.length-1))%alpha.length);
}
}
}
return caesar;
}
似乎就是caesar密码.但我在这里没有对程序进行进一步的阅读.
还是先看python代码吧
payload.py
import execjs
def get_js():
f = open('clientSideValidation.js','r')
line = f.readline()
htmlstr = ''
while line:
htmlstr += line
line = f.readline()
return htmlstr
def Call_decrypt(code):
jsfile = get_js()
ctx = execjs.compile(jsfile)
return (ctx.call('decrypt',code))
def main():
decrypted = ''
coupons = ["nvojubmq", "emph", "sfwmjt", "faopsc", "fopttfsq", "pxuttfsq"];
print(len(coupons))
for coupon in coupons:
decrypted = Call_decrypt(coupon)
print(decrypted)
if __name__ == '__main__':
main()
整个代码的逻辑还是很简单的
就是将coupons里的coupon一个一个的通过调用js里的decrypt()函数得到结果然后将结果输出.结果肯定能得到我们要在页面输入的coupon.