DHS NOC MNC Poor Security Examples

nThe Media Monitoring Capability of the The Department of Homeland Security’s National Operations Center is tasked with keeping existing situation summaries for both domestic and international events up to date with open source media information. Their second mission is “to constantly monitor all available open source information with the goal of expeditiously alerting the NOC Watch Team and other key Department personnel of emergent situations”. This means monitoring both various online news sites as well as social networking.

nn

Through a Freedom of Information Act request their Analyst’s Desktop Binder (4.4 MB PDF) was made publicly available. This is essentially the employee manual for MMC analysts, describing how to preform their job. There are quite a few very interesting tid bits in it such as the list of keywords and search terms used when searching social media sites.

nnnnn

Section 2.6 beginning on page 14 lists credible sources broken out into various tiers. Local affiliates of the major networks are considered first tier sources and don’t require any additional corroboration prior to release. Meanwhile, all blogs “even if they are of a serious, political nature,” are considered third tier sources and must be corroborated by a first tier source.

nn

Also of interest were screen shots of various interfaces they use such as the Item Of Interest (IOI) report screen used to log an article and useful metadata.

nn

nn

The real problem with this document is the peak inside Homeland Security at how they do things.

nn

Near the end, in section 8 ‘Usernames, Passwords & Contact Information,’ we see that a common username and password are shared amongst analysts to log in to computers, shared drives, DHS email, and more.

nn

nn

I am interested in the twitter information in this section. @DHSNOCMMC1 is a protected twitter account with no tweets and following 339 users. I’d love to see the followers list but I’m sure it is filled with just a lot of boring traditional news organizations.

nn

Jumping back a bit, to section 7, we find something even worse. This section is called “HSIN REDACTED Connection Instructions.” Here we see that REDACTED is a system that is so vital to our security that even it’s name must not be known.

nn

nn

See?!? It’s obvious even to my seven year old that this is a system so vital to keep secret that even the name must be secret.

nn

If one continues reading this section you come across this very surprising passage:

nn

nn

For those using screen readers due to blindness or those not trusting their eyes, this is the sentence in that image:

nn

After clicking on next, the following screen will appear and you must select “Accept for all sessions”

nn

This is followed by an image of an invalid SSL certificate warning dialog. All along experts have worried about teaching everyone’s mother not to blindly accept invalid certificate warnings. If Homeland Security is instructing their analysts to blindly accept invalid SSL certificate warnings then not only have we lost the war, the enemy is dancing on our grave as the baby jesus cries dark tears in the corner.

n

Thermostat RRD display with Javascript

In the last post I described my new Filtrete 3M-50 thermostat and my data collection using a script from a wiki. I wanted an easy way to get values for datapoints on the graphs and have been looking for a use for javascriptRRD since discovering it a year or more ago.

nn

I ended up having to modify the library slightly to get it to pass the yaxes option on to flot. My source is over on github.

nn

nn

You can see the real time data over here.

n

Tweeting Thermostat

nn

I recently replaced the thermostat in our new house with a Filtrete 3M-50. This thermostat has a wifi module and is available at your local Home Depot for $99. I’d been aware of it for a while but had planned on purchasing the $250 nest. The turning point for me came one even as I was going to bed. I was hot, the heat was running and I chose to turn the fan on instead of going downstairs and adjusting the thermostat. In my defense, I knew the thermostat would switch to night mode in another 45 minutes and reduce the set point but I was still wasting energy.

nn

Comparing the Filtrete to the nest the main features you are missing out on are:

nnnnn

    n

  • automatic occupancy detection
  • n

  • humidity detection
  • n

  • automatic schedule learning
  • n

nnn

Automatic scheduling is a big win for the average person but our schedule isn’t static enough for this to be much benifit to us. The location of our thermostat is about the best place for a thermostat, but not for occupancy detection so this feature isn’t missed. I’m a bit sad with the loss of humidity detection, the next model up Filtrete has it for $200 but it’s not a deal breaker.

nn

The real win for geeks with a WIFI thermostat isn’t the iPhone or Android Apps, it’s the ability to interface with it and do geeky things. The Filtrete 3M-50 is a rebadged Radio Thermostat Company of America CT30. Radio Thermostat has the API documentation hidden on their website in the latest news section. Scroll to the bottom of the page and click the ‘I Accept’ checkbox. There is also a 3rd party wiki with API documentation and sample code.

nn

I started with the poller.pl script available on the wiki to go from nothing to something quickly. There’s a lack of error checking in it and the non CPANed Radio::Thermostat module available on that page but it gets you up and running quickly.

nn

nn

After this, I wrote a simple script to tweet daily thermostat information.

nn

(tweetstat.pl) download
n

1n2n3n4n5n6n7n8n9n10n11n12n13n14n15n16n17n18n19n20n21n22n23n24n25n26n27n28n29n30n31n32n33n34n35n36n37n38n39n40n41n42n43n44n45n46n47n48n49n50n51n52n53n54n55n56n57n58n59n60n61n62n63n64n65n66n67n68n69n70n71n72n73n74n75n76n77n78n79n80n81n82n83n84n85n86n87n88n89n90n91n92n93n94n95n96n97n98n99n100n101n
#!/usr/bin/perl nnuse 5.010;nuse strict;nuse warnings;nnuse RRDs;nuse DateTime;nuse Net::Twitter;nuse Mojo::UserAgent;nuse List::Util 'sum';nnmy $runtime  = get_runtime_string();nmy $averages = get_averages_string();nndie unless $runtime && $averages;nnmy $tweet = "Yesterday $averages with $runtime.";nsay $tweet;nnmy $consumer_key    = '';nmy $consumer_secret = '';nmy $token           = '';nmy $token_secret    = '';nnmy $thermostat_url  = 'http://10.8.8.98/tstat/datalog';nmy $rrd_path        = '/home/michael/srv/therm/poller/data/temperature.rrd';nnmy $nt = Net::Twitter->new(n    traits   => [qw/OAuth API::REST/],n    consumer_key        => $consumer_key,n    consumer_secret     => $consumer_secret,n    access_token        => $token,n    access_token_secret => $token_secret,n);nn$nt->update($tweet);nnnsub get_runtime_string {n    my $ua = Mojo::UserAgent->new;n    my $res = $ua->get($thermostat_url)->res;nn    die "Didn't get runtimes for yesterday" unless $res;nn    my $data = $res->json;n    return build_runtime_string('heat', $data->{ yesterday } )n        || build_runtime_string('cool', $data->{ yesterday } )n        || "no heat or A/C used";n}nnsub build_runtime_string {n    my ($mode, $data)  = @_;n    my $times = $data->{ $mode . '_runtime' };n    return unless $times->{ hour } || $times->{ minute };n    return sprintf '{7e898290d39a0d5231795fca98f9d583658ec52d7dd28242e01977702bb4ac4e}sing runtime of {7e898290d39a0d5231795fca98f9d583658ec52d7dd28242e01977702bb4ac4e}i:{7e898290d39a0d5231795fca98f9d583658ec52d7dd28242e01977702bb4ac4e}02i',n        $mode, $times->{ hour }, $times->{ minute };n}nnsub get_averages_string {n    my $yesterday = DateTime->now()->subtract( days => 1);nn    my $start_of_day = DateTime->new(n        year    => $yesterday->year,n        month   => $yesterday->month,n        day     => $yesterday->day,n        hour   => 0,n        minute => 0,n        second => 0,n        time_zone => 'America/New_York'n    );nn    my $end_of_day = $start_of_day->clone->add( hours => 24 );nn    my ($start,$step,$names,$data) = RRDs::fetch (n        $rrd_path,n        'AVERAGE',n        '-s ' . $start_of_day->epoch,n        '-e ' . $end_of_day->epochn    );nn    if (my $error = RRDs::error) {n        die "Error reading RRD data: $error";n    }nn    my (@ext_temp, @int_temp);n    for my $row (@$data) {n        next unless grep { $_ } @$row;n        my ($outside, $inside) = @$row[2, 5];n        push @ext_temp, $outside;n        push @int_temp, $inside;n    }nn   return  sprintf "averaged {7e898290d39a0d5231795fca98f9d583658ec52d7dd28242e01977702bb4ac4e}.1fF outside and {7e898290d39a0d5231795fca98f9d583658ec52d7dd28242e01977702bb4ac4e}.1fF inside",n        average( @ext_temp), average(@int_temp);n}nnsub average {n    my $list = shift;n    return sum(@$list) / @$list;n}n

nnn

Tweets look like:

nn

    n

  • Yesterday averaged 59.5F outside and 67.9F inside with no heat or A/C used.
  • n

  • Yesterday averaged 64.2F outside and 70.1F inside with heating runtime of 0:17.
  • n

  • Yesterday averaged 58.9F outside and 69.0F inside with heating runtime of 0:31.
  • n

nnn

You can follow my house on Twitter as @mikegrbs_house.

n

Migrating Post Tags from WordPress to Octopress

I’ve migrated from WordPress to Octopress and used the Jekyll wordpress migrator to move my posts over. Unfortunately, this doesn’t preserve post tags. The output looks like this:

nn

1n2n3n4n5n6n7n8n
---nlayout: postntitle: Devops w/ Perl @ Linode PPW Talk Slidesnwordpress_id: 330nwordpress_url: http://michael.thegrebs.com/?p=330ndate: 2011-10-27 14:46:31 -04:00n---nEarlier this month I gave a talk about...n

nnn

Having the wordpress post id means extracting the post tags from the db should be quite easy. First we define our desired output:

nn

1n2n3n4n5n6n7n8n9n
---nlayout: postntitle: Devops w/ Perl @ Linode PPW Talk Slidesnwordpress_id: 330nwordpress_url: http://michael.thegrebs.com/?p=330ndate: 2011-10-27 14:46:31 -04:00ntags: geek perl slidesn---nEarlier this month I gave a talk about ...n

nnn

The tags field really can appear anywhere in this YAML fragment but I chose to throw it at the end. With 103 posts to loop over, run a query and insert a new line a short script makes sense. The real win for our script though is using the Tie::File module which presents each file as an array with an element for each line.

nnnnn

From there it’s simply a matter of reverse engineering the WordPress schema to come up with a query that will return a space delimited list of tags for a given post id.

nn

1n2n3n4n5n
SELECT GROUP_CONCAT(t.`name` SEPARATOR " ") FROM `wp_term_relationships` rnINNER JOIN `wp_term_taxonomy` tax ON r.`term_taxonomy_id` = tax.`term_taxonomy_id`nINNER JOIN `wp_terms` t ON tax.`term_id` = t.`term_id`nWHERE r.`object_id` = ?nAND tax.`taxonomy` = "post_tag";n

nnn

Throw that query in a script that iterates over the list of files and uses Tie::File to add a line to the post and we get:

nn

(word2octo-tags.pl) download
n

1n2n3n4n5n6n7n8n9n10n11n12n13n14n15n16n17n18n19n20n21n22n23n24n25n26n27n28n29n30n31n32n33n34n35n36n37n38n39n40n41n42n43n44n45n46n47n48n49n
#!/usr/bin/perl nnuse 5.010;nuse strict;nuse warnings;nnuse DBI;nuse Tie::File;nnmy $path_to_posts = 'source/_posts';nnmy $dbh = DBI->connect('DBI:mysql:db_name:db_host','db_user','db_pass');nnmy $get_tags = $dbh->prepare(q{n    SELECT GROUP_CONCAT(t.`name` SEPARATOR " ") FROM `wp_term_relationships` rn    INNER JOIN `wp_term_taxonomy` tax ON r.`term_taxonomy_id` = tax.`term_taxonomy_id`n    INNER JOIN `wp_terms` t ON tax.`term_id` = t.`term_id`n    WHERE r.`object_id` = ?n    AND tax.`taxonomy` = "post_tag";n    });nnnfor my $file (glob "$path_to_posts/*.markdown") {n    say $file;n    add_tags_to_file($file);n}nnsub add_tags_to_file {n    my $filename = shift;n    tie my @file, 'Tie::File', $filename or die "No tie: $!";n    my $tags;n    while (my ($rec, $data) = each @file) {n        if ($data =~ m/^wordpress_id: (d+)$/) {n            $tags = get_tag($1);n        }n        if( $data =~ /^date:/) {n            splice @file, $rec + 1, 0, $tags if $tags;n            return;n        }nn    }n}nnsub get_tag {n    my $post = shift;n    $get_tags->execute($post);n    my ($tags) = $get_tags->fetchrow_array();n    return "tags: " . $tags if $tags;n}n

nn