docker pull wordpress<span class="token punctuation">:</span><span class="token number">4.6</span><span class="token punctuation">.</span><span class="token number">1</span> docker pull mysql docker run <span class="token operator">--</span>name wp<span class="token operator">-</span>mysql <span class="token operator">-</span>e MYSQL_ROOT_PASSWORD<span class="token operator">=</span>hellowp <span class="token operator">-</span>e MYSQL_DATABASE<span class="token operator">=</span>wp <span class="token operator">-</span>d mysql docker run <span class="token operator">--</span>name wp <span class="token operator">--</span>link wp<span class="token operator">-</span>mysql<span class="token punctuation">:</span>mysql <span class="token operator">-</span>d wordpress
2.漏洞分析
我们先随便下载一个主题:
wget https<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>downloads<span class="token punctuation">.</span>wordpress<span class="token punctuation">.</span>org<span class="token operator">/</span>theme<span class="token operator">/</span>illdy<span class="token number">.1</span><span class="token punctuation">.</span><span class="token number">0.29</span><span class="token punctuation">.</span>zip unzip <span class="token operator">-</span>x illdy<span class="token number">.1</span><span class="token punctuation">.</span><span class="token number">0.29</span><span class="token punctuation">.</span>zip
然后对illdy/style.css
进行如下更改:
<span class="token comment">/* Theme Name: <svg onload=alert(1234)> ... DO NOT CHANGES HERE ... */</span>
接着更改文件夹名字再打包:
mv illdy <span class="token string">"<svg onload=alert(5678)>"</span> zip <span class="token operator">-</span>r theme<span class="token punctuation">.</span>zip <span class="token string">"<svg onload=alert(5678)>"</span>
构造好之后我们登录后台上传该主题文件,同时开始动态调试。
首先进入wp-admin/includes/class-theme-installer-skin.php
中第55-82行:
<span class="token variable">$name</span> <span class="token operator">=</span> <span class="token variable">$theme_info</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">display<span class="token punctuation">(</span></span><span class="token string">'Name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">current_user_can<span class="token punctuation">(</span></span> <span class="token string">'edit_theme_options'</span> <span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">current_user_can<span class="token punctuation">(</span></span> <span class="token string">'customize'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$install_actions</span><span class="token punctuation">[</span><span class="token string">'preview'</span><span class="token punctuation">]</span> <span class="token operator">=</span> '<span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>' . wp_customize_url( $stylesheet ) . '<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>hide-if-no-customize load-customize<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">aria-hidden</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><span class="token string">' . __( '</span>Live Preview<span class="token string">' ) . '</span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span></span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>screen-reader-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><span class="token string">' . sprintf( __( '</span>Live Preview <span class="token operator">&</span>#<span class="token number">8220</span><span class="token punctuation">;</span><span class="token operator">%</span>s<span class="token operator">&</span>#<span class="token number">8221</span><span class="token punctuation">;</span><span class="token string">' ), $name ) . '</span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span></span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></span>'<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$install_actions</span><span class="token punctuation">[</span><span class="token string">'activate'</span><span class="token punctuation">]</span> <span class="token operator">=</span> '<span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>' . esc_url( $activate_link ) . '<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>activatelink<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">aria-hidden</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><span class="token string">' . __( '</span>Activate<span class="token string">' ) . '</span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span></span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>screen-reader-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><span class="token string">' . sprintf( __( '</span>Activate <span class="token operator">&</span>#<span class="token number">8220</span><span class="token punctuation">;</span><span class="token operator">%</span>s<span class="token operator">&</span>#<span class="token number">8221</span><span class="token punctuation">;</span><span class="token string">' ), $name ) . '</span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span></span><span class="token markup"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></span>'<span class="token punctuation">;</span>
其中$theme_info
的值如下:
其中stylesheet
和template
的值为我们更改的文件夹名,headers.Name
为更改的style.css
中的Name
。$theme_info
中有我们可控的payload,其调用display
函数后赋值给$name
,$name
直接与html拼接,所以关键点在display
函数上,动态调试跟进到wp-includes/class-wp-theme.php
中第630-646行:
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">display<span class="token punctuation">(</span></span> <span class="token variable">$header</span><span class="token punctuation">,</span> <span class="token variable">$markup</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token variable">$translate</span> <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$value</span> <span class="token operator">=</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">get<span class="token punctuation">(</span></span> <span class="token variable">$header</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token boolean">false</span> <span class="token operator">===</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$translate</span> <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token function">empty<span class="token punctuation">(</span></span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token operator">!</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">load_textdomain<span class="token punctuation">(</span></span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token variable">$translate</span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$translate</span> <span class="token punctuation">)</span> <span class="token variable">$value</span> <span class="token operator">=</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">translate_header<span class="token punctuation">(</span></span> <span class="token variable">$header</span><span class="token punctuation">,</span> <span class="token variable">$value</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$markup</span> <span class="token punctuation">)</span> <span class="token variable">$value</span> <span class="token operator">=</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">markup_header<span class="token punctuation">(</span></span> <span class="token variable">$header</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token variable">$translate</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$value</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
由之前的调用可知,这里的$header
的值为Name
。首先看$this-get($header)
,在wp-includes/class-wp-theme.php
中第594-617行:
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">get<span class="token punctuation">(</span></span> <span class="token variable">$header</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">headers_sanitized</span><span class="token punctuation">[</span> <span class="token variable">$header</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">sanitize_header<span class="token punctuation">(</span></span> <span class="token variable">$header</span><span class="token punctuation">,</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">headers</span><span class="token punctuation">[</span> <span class="token variable">$header</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">return</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">headers_sanitized</span><span class="token punctuation">[</span> <span class="token variable">$header</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
这里省略了与漏洞无关的部分,程序进入了$this->sanitize_header
,在wp-includes/class-wp-theme.php
第661-705行:
<span class="token keyword">private</span> <span class="token keyword">function</span> <span class="token function">sanitize_header<span class="token punctuation">(</span></span> <span class="token variable">$header</span><span class="token punctuation">,</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span> <span class="token variable">$header</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">case</span> <span class="token string">'Name'</span> <span class="token punctuation">:</span> <span class="token keyword">static</span> <span class="token variable">$header_tags</span> <span class="token operator">=</span> <span class="token keyword">array</span><span class="token punctuation">(</span> <span class="token string">'abbr'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token keyword">array</span><span class="token punctuation">(</span> <span class="token string">'title'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token boolean">true</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'acronym'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token keyword">array</span><span class="token punctuation">(</span> <span class="token string">'title'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token boolean">true</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'code'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">'em'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">'strong'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$value</span> <span class="token operator">=</span> <span class="token function">wp_kses<span class="token punctuation">(</span></span> <span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token variable">$header_tags</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token punctuation">}</span>
这里执行了Name
这个分支,可以看到程序使用wp_kses
对$value
的值进行了过滤,仅允许$header_tags
中的html符号,所以我们headers.Name
的值<svg onload=alert(1234)>
是不合法的,$value
值被赋为空。
然后程序回到了display
函数,根据动态调试可以知道程序执行了$value = $this->markup_header( $header, $value, $translate );
这个条件分支,再跟进,在wp-includes/class-wp-theme.php
中第720-748行:
<span class="token keyword">private</span> <span class="token keyword">function</span> <span class="token function">markup_header<span class="token punctuation">(</span></span> <span class="token variable">$header</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token variable">$translate</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span> <span class="token variable">$header</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token string">'Name'</span> <span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">empty<span class="token punctuation">(</span></span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token variable">$value</span> <span class="token operator">=</span> <span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">get_stylesheet<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token keyword">return</span> <span class="token variable">$value</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>