分類  >  Web前端 >

替WebGoat添加課程——HTTP Parameter Pollution

tags:    時間:2013-12-10 09:42:30
為WebGoat添加課程——HTTP Parameter Pollution

WebGoat本身有專門一個課程用來介紹如何添加一個新的課程,但是估計是這個課程長期沒有人維護的關係,我再使用WebGoat 5.4試圖添加一個課程的時候發現有些細節的地方與WebGoat裡面介紹的步驟有些不一致或者是WebGoat裡面沒有提到的,所以把我的步驟記錄下來。

 

我添加的課程是HTTP參數污染(HTTP Parameter Pollution, HPP)這個漏洞相關的課程。關於這個漏洞的詳細信息可以參閱我的另外一篇文章:http://blog.csdn.net/eatmilkboy/article/details/6761407

 

準備環境

要為WebGoat添加課程需要使用WebGoat的源代碼,以及相關的編譯環境。

WebGoat的源代碼可以使用SVN進行下載,在這裡:http://code.google.com/p/webgoat/source/checkout可以看到如何下載代碼的相關說明。

WebGoat需要使用MAVEN進行編譯,這裡我使用JDK1.6.31MAVEN 2.2.1WebGoat源代碼下載下來后可以直接進入WebGoat的源代碼所在目錄使用如下命令進行編譯來確保編譯環境配置正確:

mvn compile

 

創建新課程步驟

1.  為新課程添加源代碼

新課程的源代碼路徑為:<WebGoat Path>\src\main\java\org\owasp\webgoat\lessons\

我們為HTTP Parameter Pollution這個漏洞增加一個新的java文件,命名為HTTPParameterPollution.java

         這個新課程的類需要繼承LessonAdapter,主要實現下面幾個介面:

  • public String getTitle()

                   這個介面設置課程的標題,設置好的標題在課程頁面的相應地方會有顯示。

 

  •     protected List<String> getHints(WebSession s)

               這個介面設置課程的提示,在用戶點擊WebGoat的「提示」按鈕後會顯示課程的相應提示。

 

  •     protected Category getDefaultCategory()

                   這個介面用來設置課程需要放置在哪個菜單項下面。比如我們為這個介面返回Category.GENERAL常量,那麼我們的課程就會被放置到「General」菜單項下面。

 

  •     protected Integer getDefaultRanking()

                   這個介面返回一個整數用來表示課程在相應菜單項下面的排序的位置。可以根據前後的課程的數值返回一個合適的值。

 

  •     protected Element createContent(WebSession s)

                   這個介面是最重要的一個介面,裡面就包含了課程的完整實現,包括課程需要顯示的界面,處理用戶提交的參數,判斷課程是否完成等等。

 

  •     public void handleRequest(WebSession s)

                   這個介面通常不需要我們自己實現,直接使用父類的實現就好。只是我們這個課程比較特殊,父類的實現無法滿足我們的需求,所以才自己實現了下。

 

         最後完整的代碼如下所示。

package org.owasp.webgoat.lessons;  import java.util.*; import org.apache.ecs.*; import org.apache.ecs.html.*; import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.ECSFactory; import javax.servlet.http.HttpServletResponse;  /***************************************************************************************************  *   *   * This file is part of WebGoat, an Open Web Application Security Project utility. For details,  * please see http://www.owasp.org/  *   * Copyright (c) 2002 - 2007 Bruce Mayhew  *   * This program is free software; you can redistribute it and/or modify it under the terms of the  * GNU General Public License as published by the Free Software Foundation; either version 2 of the  * License, or (at your option) any later version.  *   * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without  * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  * General Public License for more details.  *   * You should have received a copy of the GNU General Public License along with this program; if  * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  * 02111-1307, USA.  *   * Getting Source ==============  *   * Source for this application is maintained at code.google.com, a repository for free software  * projects.  *   * For details, please see http://code.google.com/p/webgoat/  *   * @author EatMilkBoy  * @created August 06, 2012  */   public class HTTPParameterPollution extends LessonAdapter { 	// define a constant for the field name 	private final static String COURSE_ID = "course_id"; 	private final static String COURSE_NAME = "course_name"; 	private final static String ACTION = "action"; 	private final static String SURVEY_RESULT = "survey_result"; 	 	private List<String> CourseList; 	private int Step; 	 	private boolean IsNumber(String s) 	{ 		try 		{ 			Integer.parseInt(s); 			return true; 		} 		catch (Exception e) 		{ 			return false; 		} 	} 	 	public void handleRequest(WebSession s) 	{ 		// Setting a special action to be able to submit to customized URI 		int action = s.getParser().getIntParameter(ACTION, 0); 		String course_id = s.getParser().getRawParameter(COURSE_ID, ""); 		String course_name = s.getParser().getStringParameter(COURSE_NAME, ""); 		 		Form form; 		 		CourseList = new ArrayList<String>(); 		CourseList.add("HTTP Basic"); 		CourseList.add("HTTP Splitting"); 		CourseList.add("HTTP Parameter Pollution"); 		 		if (action == 1 && CourseList.contains(course_name)) 		{ 			form = new Form("attack?" + "Screen=" + String.valueOf(getScreenId()) + "&menu=" + getDefaultCategory().getRanking().toString() + "&" + COURSE_ID + "=" + course_id, Form.POST).setName("form").setEncType(""); 			Step = 2; 		} 		else 		{ 			form = new Form("attack?" + "Screen=" + String.valueOf(getScreenId()) + "&menu=" + getDefaultCategory().getRanking().toString(), Form.POST).setName("form").setEncType(""); 			Step = 1; 		} 		 		form.addElement(createContent(s));  		setContent(form); 	} 	 	protected Element createContent(WebSession s) 	{ 		ElementContainer ec = new ElementContainer(); 		try 		{ 			// get some input from the user -- see ParameterParser for details 			String course_id = s.getParser().getRawParameter(COURSE_ID, ""); 			String course_name = s.getParser().getStringParameter(COURSE_NAME, ""); 			int action = s.getParser().getIntParameter(ACTION, 0); 			String survey_result = s.getParser().getStringParameter(SURVEY_RESULT, "");  			Input input; 			 			input = new Input(Input.TEXT, ACTION, action); 			input.setID(ACTION); 			input.setStyle("display:none;"); 			ec.addElement(input); 			 			if (action == 2 && IsNumber(course_id)) 			{ 				int course_id_int = Integer.parseInt(course_id); 				if (course_id_int <= CourseList.size()) 				{ 					StringBuffer msg = new StringBuffer();  					msg.append("Your survey result for \"" + CourseList.get(course_id_int - 1) + "\" is: " + survey_result); 					msg.append("\r\n\r\n");  					s.setMessage(msg.toString()); 				} 			} 			 			if (Step == 1) 			{ 			 				ec.addElement(new P().addElement(new StringElement("Please select a course to survey: "))); 				 				Select select = new Select(COURSE_NAME); 				Option Default = new Option("Please make a selection"); 				Default.addElement("Please make a selection"); 				if (!CourseList.contains(course_name)) 				{ 					Default.setSelected(true); 				} 				select.addElement(Default); 				select.setID(COURSE_NAME); 				 				int real_course_id = 0; 				for (int i=0; i<CourseList.size(); i++) 				{    					String name = CourseList.get(i); 					Option CourseItem = new Option(name); 					CourseItem.addElement(name); 					if (course_name.equals(name)) 					{ 						CourseItem.setSelected(true); 						real_course_id = i + 1; 					} 					select.addElement(CourseItem); 				} 			 				select.setOnChange("document.getElementById('" + COURSE_ID + "').value = document.getElementById('" + COURSE_NAME + "').selectedIndex"); 			 				ec.addElement(select); 				 				input = new Input(Input.TEXT, COURSE_ID, real_course_id); 				input.setID(COURSE_ID); 				input.setStyle("display:none;"); 				ec.addElement(input); 				 				input = (Input)ECSFactory.makeButton("Survey"); 				input.setOnClick("document.getElementById('" + ACTION + "').value = 1"); 				ec.addElement(input); 			} 			else 			{ 				if (action == 1) 				{ 					String[] arrTokens = course_id.split("&"); 					if (IsNumber(arrTokens[0])) 					{ 						for (int i = 1; i < arrTokens.length; i++)  						{ 							System.out.println("Token: " + arrTokens[i]); 							if (arrTokens[i].matches("^survey_result=.*")) 							{ 								s.setMessage("Good job!<br>This lesson has detected your successful attack, make a select other than you specified survey result and click \"Submit\" to view the result.<br>"); 								// Tell the lesson tracker the lesson has completed. 								// This should occur when the user has 'hacked' the lesson. 								makeSuccess(s); 								break; 							} 						} 					} 				} 				 				ec.addElement(new StringElement("Please provide your opinion for course: <b>" + course_name + "</b>")); 				ec.addElement(new BR()); 				ec.addElement(new BR());  				input = new Input(Input.RADIO, SURVEY_RESULT, "Good"); 				input.addElement("Good"); 				if (action != 1 || (action == 1 && survey_result.equals("Good"))) 					input.setChecked(true); 				ec.addElement(input); 				ec.addElement(new BR()); 				ec.addElement(new BR());  				input = new Input(Input.RADIO, SURVEY_RESULT, "So-so"); 				input.addElement("So-so"); 				if (action == 1 && survey_result.equals("So-so")) 					input.setChecked(true); 				ec.addElement(input); 				ec.addElement(new BR()); 				ec.addElement(new BR()); 				 				input = new Input(Input.RADIO, SURVEY_RESULT, "Bad"); 				input.addElement("Bad"); 				if (action == 1 && survey_result.equals("Bad")) 					input.setChecked(true); 				ec.addElement(input); 				ec.addElement(new BR()); 				ec.addElement(new BR()); 				 				input = (Input)ECSFactory.makeButton("Submit"); 				input.setOnClick("document.getElementById('" + ACTION + "').value = 2"); 				ec.addElement(input); 			} 		} 		catch (Exception e) 		{ 			s.setMessage("Error generating " + this.getClass().getName()); 			e.printStackTrace(); 		} 		return (ec); 	}  	protected Category getDefaultCategory() 	{ 		return Category.GENERAL; 	} 	 	private final static Integer DEFAULT_RANKING = new Integer(30);  	protected Integer getDefaultRanking() 	{ 		return DEFAULT_RANKING; 	}  	protected List<String> getHints(WebSession s) 	{  		List<String> hints = new ArrayList<String>(); 		hints.add("Try inject code into course_id parameter."); 		return hints;  	}  	public String getTitle() 	{ 		return ("HTTP Parameter Pollution"); 	} }


 

一旦代碼完成,就可以再次在WebGoat的目錄下面執行MAVEN的編譯命令進行編譯。編譯好的針對我們課程的class文件可以在<WebGoat Path>\target\classes\org\owasp\webgoat\lessons目錄下面看到。

2.  創建課程計劃

課程計劃是當用戶在WebGoat頁面上點擊「Lesson Plan」之後出現的文本,實際上是以HTML格式文件的一個片段存在,可以仿照其它課程的樣式書寫我們的樣式。這邊需要注意的是文件名需要和課程的class文件名保持一致。比如我們的課程的class文件名為HTTPParameterPollution.class,那麼我們的課程計劃的文件名就應該是HTTPParameterPollution.html。注意大小寫也要保持一致。

<div align="Center">  <p><b>Lesson Plan Title:</b> How to Perform HTTP Parameter Pollution </p>  </div>   <p><b>Concept / Topic To Teach:</b> </p>  This lesson teaches how to perform HTTP Parameter Pollution attacks.  <br />  <div align="Left">  <p> <b>How the attack works:</b> </p> <p>HTTP Parameter Pollution attack consists of injecting encoded query string delimiters into existing HTTP parameters.</p> <p>If application does not sanitize its inputs, HPP can be used to launch client-side or server-side attacks.</p> <p>Attacker may be able to override existing parameter values, inject a new parameter or exploit variables out of a direct reach</p> </div> <p><b>General Goal(s):</b> </p> <!-- Start Instructions --> <p>This lesson focus on HPP client side attack.</p> <p>Select a class name from the list and click the "Survey" button, the server will show a form for you to submit your opinion for this course. And also when you submit your opinion server will also display the result to you.</p> <p>You should able to use HPP to launch client side attack, the goal is to make a survey result for a class is always a fixed value no matter user choose.</p> <!-- Stop Instructions -->  


 

3.  創建課程解決方案

課程的解決方案以完整HTML文件的形式存在,同樣需要注意在文件命名的時候與class文件保持一致。實際上其文件名應該與課程計劃的文件名一樣,只是到時候部署的時候會放到不同的文件夾裡面。在解決方案裡面也可以包含一些插圖,在HTML文件裡面設置好這些圖片的相對路徑之後可以一起部署到WebGoat裡面去。

關於這裡增加的這個課程的解決方案參看本文結尾。

 

部署新課程

到現在我們準備新增的課程的所有材料都準備好了,可以部署到WebGoat的運行環境裡面去了。在WebGoat標準版中,當WebGoat第一次運行之後(即部署過原始的WebGoat.war文件之後),把我們準備的各文件放置到如下目錄:

課程計劃放置到<WebGoat標準版路徑>\tomcat\webapps\webgoat\lesson_plans\English

解決方案放置到<WebGoat標準版路徑>\tomcat\webapps\webgoat\lesson_solutions

課程源代碼放置到<WebGoat標準版路徑>\tomcat\webapps\webgoat\WEB-INF\classes\java\org\owasp\webgoat\lessons

課程class文件放置到<WebGoat標準版路徑>\ tomcat\webapps\webgoat\WEB-INF\classes\org\owasp\webgoat\lessons

然後重新啟動WebGoat標準版之後就可以看到我們新增加的課程了。

 

添加這個課程所需要的材料可以從這裡下載到:

http://download.csdn.net/detail/eatmilkboy/4741693

 

課程解決方案

同時也附上我們這個課程的解決方案。

這個課程是給出了一個頁面用來讓用戶對WebGoat的一些課程進行評價是好還是不好。目標是利用HPP的漏洞讓用戶不管選擇什麼樣的評價,最後的結果都是好。

我們可以先進行一下操作然後使用TamperData來觀察下瀏覽器與伺服器之間的數據交互。選擇一個課程並提交后,TamperData抓取到的輸入如下圖所示:

然後課程返回用於一個評價的界面:

提交評價之後可以從TamperData看到提交的請求如下圖所示:

在這裡我們可以看到其提交請求的URL裡面,course_id這個參數正好是我們第一步提交的course_id的參數。所以我們可以考慮對這個參數進行注入。

利用TampderData攔截在第一步選擇課程時提交的參數,把course_id的值改為1%26survey_result%3DGood,提交后就可以看到課程已經識別到了我們已經成功注入了這個參數,這時候,不管選擇的評價是好還是壞,最後的結果都會是好。

我們可以再隨便選擇一個評價來看看提交給伺服器的請求,可以看到這次提交的請求裡面URL中已經多了一個survey_result=Good的參數,這正是我們注入的結果。

推薦閱讀文章

Bookmark the permalink ,來源:互聯網