ZAP Custom En/Decoder 만들기

ZAP의 확장성은 Scripting Engine의 파워에서 나옵니다. URL, HTML, Base64 등 테스팅 단계에선 인/디코딩을 하는 경우가 굉장히 많은데요. 이 때 사용하는 Encode/Decode/Hash 기능 또한 Scripting으로 확장할 수 있습니다.

사실 ZAP 2.10 버전(2020년 말)에 추가된 기능이지만 당시에는 별도로 리뷰하지 않았었고, 이제서야 글로 풀어봅니다.

왜 더 만드나요?

보안 테스팅 시 잘 알려지지 않은 인코딩을 만날 수도 있고, 키가 알려진 암복호화 로직이 존재할 수도 있습니다. 또한 동적인 값을 통해 인코딩이 필요한 경우도 있습니다. 이럴 때 스크립팅을 통해 기능을 확장한다면 조금 더 편안하게 테스팅할 수 있습니다.

또한 한번 만들어진 결과는 파일로 관리할 수 있기 때문에 쉽게 재 사용할 수도 있고, 공유하여 사용하는 등의 액션도 가능합니다. 그리고 테스팅 이외에 그냥 문자열 처리 목적으로도 충분히 쓸만합니다 :D

EDH

Encode/Decode/Hash 기능은 Command + E 를 통해 단축키로 열거나 상단 메뉴바의 Tools → Encode/Decode/Hash를 눌러 열 수 있습니다.

Structure

맨 위에 Input box가 존재하며 아래 Tab들이 있고, 각 Tab에는 Output을 표시하는 여러개의 Panel이 존재합니다. 하나의 Tab에 속한 여러 Panel은 Input이 들어왔을 때 동시에 처리하여 결과를 보여줍니다.

Default

기본으로 제공해주는 Encoder, Decoder와 Hasher입니다.

Encoder Decoders Hashers
2 byte Illegal UTF-8 ASCII Hex Decode MD5
3 byte Illegal UTF-8 Base 64 Decode SHA1
4 byte Illegal UTF-8 Base 64 URL Decode SHA256
ASCII Hex Encode HTML Decode  
Base 64 Encode JavaScript Decode  
Base 64 URL Encode URL Decode  
HTML Encode Full URL Decode  
JavaScript Encode    
URL Encode    
Full URL Encode    
Unescaped Unicode Text    

Scripting

Basic

EDH가 스크립팅을 지원하기 때문에 우리는 원하는 Encoder, Decoder, Hasher를 추가할 수 있습니다. 언어는 Js, Ruby, Python, Groovy 등 ZAP에서 제공하는 스크립팅을 모두 지원하고 Java에 선언된 process 함수를 통해 동작을 구성할 수 있습니다.

  • @param {EncodeDecodeScriptHelper}
  • @param {String} value
  • @returns {EncodeDecodeResult}
    • e.g return helper.newResult(result).

아래는 js 코드인데 process 함수에 a를 b로 치환하는 로직을 넣었습니다.

function process(helper, value){
    return helper.newResult(value.replaceAll("a", "b").trim());
}

스크립트는 Encode/Decode 카테고리로 넣어주시고 Enable 해줍시다.

그리고 Cmd + e 를 통해 EDH를 열어준 후 테스트를 위해 Tab을 하나 만들어줍시다. 개인적으로 필요할 때 마다 자주 만들어서 사용합니다.

그리고, 새로운 Output도 만들어줍시다. 이 때 아까 만든 스크립트를 지정합니다.

이후에 해당 탭에서 작성하는 데이터는 우리가 만든 코드를 통해 En/Decode 됩니다.

New Hasher

하나 예시로 더 해보죠. HashProcessor를 통해서 기존에 제공하지 않는 해시를 추가해볼 수 있습니다. 꼭 predefined 되지 않아도 Java, Ruby 등 언어에서 각자의 패키지들을 로드해서 사용할 수 있기 때문에 여러가지 형태로 만들어갈 수 있습니다.

var Hasher = Java.type("org.zaproxy.addon.encoder.processors.predefined.HashProcessor");

function process(helper, value){
	var output = new Hasher("sha3-256").process(value).getResult();
	return helper.newResult(output);
}

Languages

Ruby

def process(helper, vaule)
	return helper.newResult(vaule.gsub('a','b'))
end

Python

def process(helper, value):
    return helper.newResult(value);

JS(Nashorn)

function process(helper, value){
	return helper.newResult(value.replaceAll("a", "b").trim());
}

JS(Graal)

function process(helper, value){
	return helper.newResult(value);
}

Groovy

import org.zaproxy.addon.encoder.processors.EncodeDecodeResult
import groovy.transform.Field

@Field final int test =  1

EncodeDecodeResult process(EncodeDecodeScriptHelper helper, String value){
    return new helper.newResult(String.valueOf(test++) + "|" + value)
}