m0leCon teaser 2022 - ptmList
めでたいことに人生初、義務Writeupが発生したので、簡単ですがせっかくなので日本語で書いたものは残しておきます。
ゲームのアイテム画面のようなUIのPwnです。 多数のアイテムの中から自分のリストを作成し、並べ替えや削除などの操作ができる機能があります。
バグは2つあります。
- アイテムを並べ替える関数は、並べ替える2つのアイテムの種類が同じとき、それらのアイテムをまとめてリストの長さを1短くしますが、この時元のリストの長さを確認せずに減算します。
- アイテムを削除する関数は、アイテムの数が255のアイテムを削除するとき、すべて減らそうとすると、実際には削除されないにもかかわらず、リストの長さが1短くしてしまいます。
以下は2. の該当ソースです。
最初のelse
に入る条件は、アイテムの数をすべて削除することです。例えば3つ所持しているときに3つ削除する操作をすれば入ります。
続くwhile
の条件文がおかしくて、これだと「アイテムの種類が255でなく、かつアイテムの数が255でない」ならば、その数を減らすという実装になっています。つまりアイテムの数が255の場合に255個削除するという入力をすると、該当のアイテムを減らすことなくリストの最大長を減らすことができます。今回、アイテムの上限は99ですが、メニューにあるSecretGiftを使うことで、1つだけアイテムの数を255に増やすことができますので問題ないです。
void removeItem(long param_1_ptr,char *param_2_maxlen,int param_3_index,int param_4_amount)
{
...
else {
while ((*(char *)(param_1_ptr + (long)local_c * 2) != -1 &&
(*(char *)(param_1_ptr + (long)local_c * 2 + 1) != -1))) {
*(undefined *)(param_1_ptr + (long)local_c * 2) =
*(undefined *)(param_1_ptr + ((long)local_c + 1) * 2);
*(undefined *)(param_1_ptr + (long)local_c * 2 + 1) =
*(undefined *)(param_1_ptr + ((long)local_c + 1) * 2 + 1);
local_c = local_c + 1;
}
*param_2_maxlen = *param_2_maxlen + -1;
}
ただしこの機能は、リストの最大長が0のときには正しく行を選択できず、途中で落とされてしまうため使えません。
並べ替えるほうは大丈夫なので、削除の関数でリスト最大長を0まで減らした後、1度並べ替えることでリスト最大長がオーバーフローして255にすることができます。
リストのサイズが0の時の並べ替え前の様子。
box of tissues | Quantity: 255 |
---------------------------------------------------
water | Quantity: 01 |
---------------------------------------------------
---------------------------------------------------
water | Quantity: 01 |
---------------------------------------------------
Cancel
w/s move, m select second item, Esc exit
こちらが並べ替えた後。Cancelが続くのは、スタックは0xffffがしばらく続くので、アイテムの種類が255(=該当アイテムなし)として表示されているからです。
box of tissues | Quantity: 255 |
water | Quantity: 02 |
---------------------------------------------------
Cancel
---------------------------------------------------
Cancel
Cancel
Cancel
Cancel
Cancel
Cancel
Cancel
Cancel
w/s move, d delete, m move, Esc exit
あとは下のほうに行って、mainへの戻りアドレスにあたる部分をwinfuncに変えるだけです。
ASLRを切っていると、mainへの戻りアドレスが0x0000555555557986
にあり、winfuncが0x5555555575e7
あるので、以下のようにリークを利用して書き換えます。
1. アイテムの種類が0x86であるアイテムの行を探して値を確認しこれをXとする
2. アイテムの種類が0xe7であるアイテムと、1.のアイテムを並べ替える
3. 2で交換したアイテムの数をX-4にする
具体例で書きます。0x86はbuckle
というアイテムが該当、0xe7はlace
というアイテムが該当します。
まず、lace
にSecretGiftを使った状態で、上記のテクニックを使ってリストの最大長を伸ばします。
次にCancelがかなり続いた下のほうで、buckle Xを見つけます。この例だとXは57なので、53にすればちょうどwinfuncを指すはずです。
frying pan | Quantity: 47 |
bottle of soda | Quantity: 182 |
multitool | Quantity: 224 |
Cancel
box of tissues | Quantity: 00 |
---------------------------------------------------
buckle | Quantity: 57 |
---------------------------------------------------
sailboat | Quantity: 17 |
tv | Quantity: 86 |
box of tissues | Quantity: 00 |
box of tissues | Quantity: 00 |
box of tissues | Quantity: 00 |
w/s move, d delete, m move, Esc exit
mキーを使って、最初に先頭行で作ったlace 255
とbuckle 57
を交換します。
frying pan | Quantity: 47 |
bottle of soda | Quantity: 182 |
multitool | Quantity: 224 |
Cancel
box of tissues | Quantity: 00 |
---------------------------------------------------
lace | Quantity: 255 |
---------------------------------------------------
sailboat | Quantity: 17 |
tv | Quantity: 86 |
box of tissues | Quantity: 00 |
box of tissues | Quantity: 00 |
box of tissues | Quantity: 00 |
w/s move, d delete, m move, Esc exit
202引いて53にします。
frying pan | Quantity: 47 |
bottle of soda | Quantity: 182 |
multitool | Quantity: 224 |
Cancel
box of tissues | Quantity: 00 |
---------------------------------------------------
lace | Quantity: 53 |
---------------------------------------------------
sailboat | Quantity: 17 |
tv | Quantity: 86 |
box of tissues | Quantity: 00 |
box of tissues | Quantity: 00 |
box of tissues | Quantity: 00 |
w/s move, d delete, m move, Esc exit
あとはexitするとwinfuncへ飛びます。
Welcome to ptmList, the program to help you keep your shopping lists in order!
| View item list |
| View your list |
| Secret gift |
------------------
| Exit |
------------------
$ whoami
jt
$
配列伸ばしたら終わりなんだろうなあと思いながらやっていましたが、割と思い通りめちゃめちゃ伸びたので楽しかったです。