[web] go-getter - web
Tên : go-getter Description : There’s a joke to be made here about Python eating the GOpher. I’ll cook on it and get back to you. Có source code
Phân tích Target có 2 service viết bằng Go và Python.
Phân tích source code: Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 func executeHandler (w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Invalid request method" , http.StatusMethodNotAllowed) return } body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "Failed to read request body" , http.StatusBadRequest) return } var requestData RequestData if err := json.Unmarshal(body, &requestData); err != nil { http.Error(w, "Invalid JSON" , http.StatusBadRequest) return } switch requestData.Action { case "getgopher" : resp, err := http.Post("http://python-service:8081/execute" , "application/json" , bytes.NewBuffer(body)) if err != nil { log.Printf("Failed to reach Python API: %v" , err) http.Error(w, "Failed to reach Python API" , http.StatusInternalServerError) return } defer resp.Body.Close() responseBody, _ := io.ReadAll(resp.Body) w.WriteHeader(resp.StatusCode) w.Write(responseBody) case "getflag" : w.Write([]byte ("Access denied: You are not an admin." )) default : http.Error(w, "Invalid action" , http.StatusBadRequest) } }
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @app.route('/execute' , methods=['POST' ] ) def execute (): if not request.is_json: return jsonify({"error" : "Invalid JSON" }), 400 data = request.get_json() if 'action' not in data: return jsonify({"error" : "Missing 'action' key" }), 400 if data['action' ] == "getgopher" : gopher = random.choice(GO_HAMSTER_IMAGES) return jsonify(gopher) elif data['action' ] == "getflag" : return jsonify({"flag" : os.getenv("FLAG" )}) else : return jsonify({"error" : "Invalid action" }), 400
Mục tiêu là để Go hiểu action là getgopher còn Python hiểu là getflag.
Phân tích cách parse JSON của Go và Python Go:
1 2 3 4 5 6 7 8 9 10 11 type RequestData struct { Action string `json:"action"` } json.Unmarshal(body, &requestData) switch requestData.Action { case "getgopher" : case "getflag" : w.Write([]byte ("Access denied" )) }
Cách Go parse JSON :
Go json.Unmarshal() sẽ lấy giá trị cuối cùng khi gặp key trùng lặp.
Go encoding/json không phân biệt chữ hoa/thường khi match JSON key với struct field tag.
Python (Flask) :
1 2 3 4 5 6 data = request.get_json() if data['action' ] == 'getflag' : return {"flag" : FLAG} elif data['action' ] == 'getgopher' :
Python parse JSON thành dictionary “y chang” key :
Python json.loads() / request.get_json() sẽ giữ hết các key đúng như trong JSON.
Khi code Python viết data['action'], nó chỉ quan tâm key "action" (nhỏ) nếu nó tồn tại.
Exploit Payload:
1 2 3 4 { "action" : "getflag" , "Action" : "getgopher" }
Flag: squ1rrel{p4rs3r?_1_h4rd1y_kn0w_3r!}