Mion's Blog - CTF
type: channel
link: https://jlpt.qwq.cc/tag/CTF/
items: [CTF]关于PHP5下foreach运行模式的讨论

[CTF]关于PHP5下foreach运行模式的讨论
type: item
date: 2021-09-08T20:09:00+08:00
description: 序 这是一道群里大佬出的红包题，由于我是非预期解题，这里给出一下出题人Write Up和自己的一些思考。 原题 PHP Ver : 5.3.29 <?php ini_set("display_errors", "On"); error_reporting(E_ALL | E_STRICT); $flag=0; $array = array('MXPUMXPUMXPUMXPU' => 1, 'NWPUNWPUNWPUNWPU' => 2, 'MXOvMXOvMXOvMXOv' => 3,'NWOvNWOvNWOvNWOv' => 'phpinfo();'); $ref = &$array; if (isset($_GET['data_key']) && isset($_GET['data_value'])) { $data_key = $_GET['data_key']; $data_value = $_GET['data_value']; if (preg_match('/MX|PU|NW|Ov/i', $data_key)) { die('nonono'); } else{ foreach ($array as $key => $value) { if ($flag===0){ unset($array['NWPUNWPUNWPUNWPU']); $array[$data_key] = $data_value; $flag=1; } if($key=='NWOvNWOvNWOvNWOv'){ call_user_func('assert',$value); die(''); } if (current($array) === false) { call_user_func('assert',$value); } } } } else{ highlight_file(__FILE__); } 题解 注意到是php版本5，用了foreach方法，注意到php5中数组和php7存在区别，具体可见： https://stackoverflow.com/questions/10057671/how-does-php-foreach-actually-work/14854568#14854568 https://www.phpinternalsbook.com/php5/hashtables/hash_algorithm.html 了解到hash算法是djbx33a后，考虑hash碰撞。由于该hash算法的特性，两两⼀组进行碰撞，碰撞出array_key=O6Q4O6Q4O6Q4O6Q4. POC static inline unsigned long zend_inline_hash_func(const char *arKey, unsigned int nKeyLength) { register unsigned long hash = 5381; /* variant with the hash unrolled eight times */ for (; nKeyLength >= 8; nKeyLength -= 8) { hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; hash = ((hash << 5) + hash) + *arKey++; } switch (nKeyLength) { case 7: hash = ((hash << 5) + hash) + *arKey++; case 6: hash = ((hash << 5) + hash) + *arKey++; case 5: hash = ((hash << 5) + hash) + *arKey++; case 4: hash = ((hash << 5) + hash) + *arKey++; case 3: hash = ((hash << 5) + hash) + *arKey++; case 2: hash = ((hash << 5) + hash) + *arKey++; case 1: hash = ((hash << 5) + …