Swiftz协议原版

Swiftz Protocal

Swiftz is a project aims to create a portable replacement of Edusupplicant, base on the analysis on Edusupplicant 3.6.5.

The project is FOR STUDY ONLY. Attacking, hacking or any other illegal purposes are STRICTLY PROHIBITED.


Protocal version

The original analysis is based on Edusupplicant 3.6.5.

Tested compatible with Edusupplicant 3.7.8.

Implementations based on this analysis

  • SwiftzMac (for Mac OS X >= 10.8)
  • swiftz.js (for Linux/Mac, command-line, STILL IN PROGRESS)
  • Swiftoid (for Android >= 4.0.3, STILL IN PROGRESS)
  • OpenSupplicant (for Windows, stopped development for a long time)

Representation

The protocal in this documentation is written as procedure.

For example:

local:3848 -> server:3848 crypto3848
LOGIN:
  MAC as data(16)
  USERNAME as string
  PASSWORD as string
  IP as string
  ENTRY as string
  DHCP as boolean
  VERSION as string
  1. Send to remote server port 3848 from local port 3848 (all packets send via UDP).
  2. The packet is encrypted with crypto3848.
  3. The packet represents an LOGIN action (see Consts / Actions section below).
  4. The packet contains these fields (see Consts / Fields section below):
  5. MAC: Binary data, with fixed length 16 bytes
  6. USERNAME: String
  7. PASSWORD: String
  8. IP: String
  9. ENTRY: String
  10. DHCP: Boolean
  11. VERSION: String

Encoding

Charset

All strings in the protocal is in GB2312 charset.

Types

  • String: strings transport in GB2312.
  • Char: number in 1 byte. (i.e. 0xFF for 255)
  • Integer: number in 4 bytes. (i.e. 0x00 0x00 0x00 0xFF for 255)
  • Boolean: 0x00 for false, 0x01 for true.
  • Data: as it is. (i.e. 0x4A 0x21 0x39 0xC0 for 4A2139C0)

Packet

A naked (non-encrypted) packet is in this structure:

  1. 1 byte of ACTION represented what does the packet do
  2. 1 byte represented the length of whole packet
  3. 16 bytes MD5 hash
  4. 1 byte of the key of the first field
  5. 1 byte of the length of the first field (including the key and the length itself)
  6. the data of the first field
  7. 1 byte of the key of the second field (including the key and the length itself)
  8. 1 byte of the length of the second field
  9. the data of the second field
  10. ......

Note that fields' length is 2 bytes shorter than the field is.

Generate a packet

  1. Construct a packet as it's descripted above, of course, leaving those 16 bytes of MD5 hash be 16 bytes of 0x00
  2. Generate a MD5 hash of the whole packet
  3. Fill those 16 bytes with the hash you got
  4. Encrypt it of course :)

Parse a packet you recieved

  1. Decrypt it
  2. Check the MD5 hash (optional but recommanded for security)
  3. You know how to do :)

Encryption/Decryption

"crypto3848"

The crypto3848 algorithm is a very simple encryption algorithm that changes the order of every byte from ABCDEFGH to HDEFCBAG.

Here's a piece of code in JavaScript for reference:

function encrypt (buffer) {
  for (var i = 0; i < buffer.length; i++) {
    buffer[i] = (buffer[i] & 0x80) >> 6
              | (buffer[i] & 0x40) >> 4
              | (buffer[i] & 0x20) >> 2
              | (buffer[i] & 0x10) << 2
              | (buffer[i] & 0x08) << 2
              | (buffer[i] & 0x04) << 2
              | (buffer[i] & 0x02) >> 1
              | (buffer[i] & 0x01) << 7
  }
}

function decrypt (buffer) {
  for (var i = 0; i < buffer.length; i++) {
    buffer[i] = (buffer[i] & 0x80) >> 7
              | (buffer[i] & 0x40) >> 2
              | (buffer[i] & 0x20) >> 2
              | (buffer[i] & 0x10) >> 2
              | (buffer[i] & 0x08) << 2
              | (buffer[i] & 0x04) << 4
              | (buffer[i] & 0x02) << 6
              | (buffer[i] & 0x01) << 1
  }
}

"crypto3849"

Like crypto3848 but different order that from ABCDEFGH to ECBHAFDG.

function encrypt (buffer) {
  for (var i = 0; i < buffer.length; i++) {
    buffer[i] = (buffer[i] & 0x80) >> 4
              | (buffer[i] & 0x40) >> 1
              | (buffer[i] & 0x20) << 1
              | (buffer[i] & 0x10) >> 3
              | (buffer[i] & 0x08) << 4
              | (buffer[i] & 0x04)
              | (buffer[i] & 0x02) >> 1
              | (buffer[i] & 0x01) << 4
  }
}

function decrypt (buffer) {
  for (var i = 0; i < buffer.length; i++) {
    buffer[i] = (buffer[i] & 0x80) >> 4
              | (buffer[i] & 0x40) >> 1
              | (buffer[i] & 0x20) << 1
              | (buffer[i] & 0x10) >> 4
              | (buffer[i] & 0x08) << 4
              | (buffer[i] & 0x04)
              | (buffer[i] & 0x02) << 3
              | (buffer[i] & 0x01) << 1
  }
}

Flow

Startup

Just send a initialization packet to 1.1.1.8 without waiting for any response

First-run initialization

  1. Search for authorization server
  2. Get entries list

Get online

  1. Make a online request, and wait for a response
  2. If successed, some servers may also need a confirm

During you're online

  1. Make a breathe every 30 seconds
  2. Also, listen for disconnecting notification you may recieved.

Get offline

Make a offline request to end the session.

Packets

Initialize

Just send this plain text to 1.1.1.8 port 3850 via UDP.

info sock ini
  • No decryption is required.
  • No response would be make by the server.

Search for authorization server

Send

local:3848 -> 1.1.1.8:3850 crypto3848
SERVER:
  SESSION as string
  IP as string(16)
  MAC as data(16)

Receive

1.1.1.8:3850 -> local:3848 crypto3848
SERVER_RET:
  SERVER as data(4)
  UNKNOWN0D as data(4)
  • SERVER is received as 4-byte data that each byte indicates a part of an IPv4 address, e.g. AC1001B4 for 172.16.1.180.

Get entries

Send

local:3848 -> server:3848 crypto3848
ENTRIES:
  SESSION as string
  MAC as binary(16)

Receive

server:3848 -> local:3848 crypto3848
ENTRIES_RET:
  ENTRY as string
  ENTRY as string
  ...
  • It may be more than one ENTRY field.

Online

Send

local:3848 -> server:3848 crypto3848
LOGIN:
  MAC as data(6)
  USERNAME as string
  PASSWORD as string
  IP as string
  ENTRY as string
  DHCP as boolean
  VERSION as string

Receive

server:3848 -> local:3848 crypto3848
LOGIN_RET:
  SUCCESS as boolean
  SESSION as string
  UNKNOWN05 as char
  UNKNOWN06 as char
  MESSAGE as string
  UNKNOWN95 as data(24)
  UNKNOWN06 as char
  BLOCK34 as data(4)
  BLOCK35 as data(4)
  BLOCK36 as data(4)
  BLOCK37 as data(4)
  BLOCK38 as data(4)
  WEBSITE as string
  UNKNOWN23 as char
  UNKNOWN20 as char
  • Only contains SUCCESS, SESSION and MESSAGE if not successed (i.e. wrong password)
  • Will contains an unknown field UNKNOWN95 with 24 bytes of 0x00 and an unknown field UNKNOWN06 if it is in low-speed mode.
  • The length of field SESSION received is 2 bytes shorter than the field is.
  • The length of field MESSAGE received is 2 bytes shorter than the field is.

Confirm

Send

local:random -> server:3849 crypto3849
CONFIRM:
  USERNAME as string
  MAC as data(6)
  IP as string
  ENTRY as string

Receive

server:3849 -> local:random crypto3849
CONFIRM_RET
  UNKNOWN30 as data(4)
  UNKNOWN31 as data(4)
  UNKNOWN32 as char
  • The packet is sent and receive via the same random port
  • 3 bytes of 0x00 appears before the md5 checksum of the packet possibly by a BUG. The length of the whole packet is calculated with those 3 bytes included.

Breathe

Send

local:3848 -> server:3848 crypto3848
BREATHE:
  SESSION as string
  IP as string(16)
  MAC as data(16)
  INDEX as integer
  BLOCK2A as data(4)
  BLOCK2B as data(4)
  BLOCK2C as data(4)
  BLOCK2D as data(4)
  BLOCK2E as data(4)
  BLOCK2F as data(4)
  • The initial value of INDEX is 0x01000000 and increases 3 after every breathe.
  • INDEX should not be increased unless a valid BREATHE_RET is recevied, because you may lost packets in low-speed mode.

Receive

server:3848 -> local:3848 crypto3848
BREATHE_RET:
  SUCCESS as boolean
  SESSION as string
  INDEX as integer
  • The length of field SESSION received is 2 bytes shorter than the field is.

Offline

Send

local:3848 -> server:3848 crypto3848
LOGOUT:
  SESSION as string
  IP as string(16)
  MAC as data(16)
  INDEX as integer
  BLOCK2A as data(4)
  BLOCK2B as data(4)
  BLOCK2C as data(4)
  BLOCK2D as data(4)
  BLOCK2E as data(4)
  BLOCK2F as data(4)
  • The initial value of INDEX is 0x01000000 and increases 3 after every breathe.
  • INDEX should not be increased unless a valid BREATHE_RET is recevied, because you may lost packets in low-speed mode.
  • It's very like a BREATHE packet.

Receive

server:3848 -> local:3848 crypto3848
LOGOUT_RET:
  SUCCESS as boolean
  SESSION as string
  INDEX as integer
  • The length of field SESSION received is 2 bytes shorter than the field is.

Being disconnected

Once you have bean disconnected, you'll receive a packet from the server:

server:2001 -> local:4999 crypto3848
DISCONNECT:
  SESSION as string
  REASON as char
  • Possible values of REASON:
    • 0x00 - No valid breathe is made for a long time.
    • 0x01 - You're disconnected forcibly (by administrator, maybe).
    • 0x02 - You've reached your network traffic limit.
  • The length of field SESSION received is 2 bytes shorter than the field is.

Consts

Actions

// login
LOGIN = 0x01

// login result
LOGIN_RET = 0x02

// breathe
BREATHE = 0x03

// breathe result
BREATHE_RET = 0x04

// logout
LOGOUT = 0x05

// logout result
LOGOUT_RET = 0x06

// get access point
ENTRIES = 0x07

// return access point
ENTRIES_RET = 0x08

// disconnect
DISCONNECT = 0x09

// confirm login
CONFIRM = 0x0A

// confirm login result
CONFIRM_RET = 0x0B

// get server
SERVER = 0X0C

// return server
SERVER_RET = 0x0D

Fields

// username
USERNAME = 0x01

// password
PASSWORD = 0x02

// whether it is success
SUCCESS = 0x03

// unknown, appears while login successfully
UNKNOWN05 = 0x05
UNKNOWN06 = 0x06

// mac address
MAC = 0x07

// session (NOTE: wrong in return packet)
SESSION = 0x08

// ip address
IP = 0x09

// access point
ENTRY = 0x0A

// message (NOTE: wrong in return packet)
MESSAGE = 0x0B

// server ip address
SERVER = 0x0C

// unknown, appears while received server ip address
UNKNOWN0D = 0x0D

// is dhcp enabled
DHCP = 0x0E

// self-services website link
WEBSITE = 0x13

// serial no
INDEX = 0x14

// version
VERSION = 0x1F

// unknown, appears while login successfully
UNKNOWN20 = 0x20
UNKNOWN23 = 0x23

// disconnect reason
REASON = 0x24

// 4 bytes blocks, send in breathe and logout
BLOCK2A = 0x2A
BLOCK2B = 0x2B
BLOCK2C = 0x2C
BLOCK2D = 0x2D
BLOCK2E = 0x2E
BLOCK2F = 0x2F

// unknown 4 bytes blocks, appears while confirmed
BLOCK30 = 0x30
BLOCK31 = 0x31

// unknown
UNKOWN32 = 0x32

// 4 bytes blocks, appears while login successfully
BLOCK34 = 0x34
BLOCK35 = 0x35
BLOCK36 = 0x36
BLOCK37 = 0x37
BLOCK38 = 0x38
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 静气 刘艳 昨晚,孩子读《简爱》,读到简和罗切斯特的对话,兴奋之余,她模仿,模仿完,自己哈哈大笑。 ...
    朝有清云阅读 234评论 1 2
  • 加入桂军亲子晨享群第三天,我感觉潜移默化中我在的心态有所改变了。孩子周末才回家,我就通过我的学生去感受。 一大早到...
    扮好自己的角色阅读 355评论 0 3
  • 2016.10.19 承接之前的一篇235.朝花夕拾45~当年的国庆书市,那年我和李冬骑车去劳动人民文化宫书市。 ...
    摹喵居士阅读 292评论 0 0
  • 一个宿迁的好兄弟,在他婚礼之后便一直没有和他见面了,上周末他正好去上海采购设备,路过苏州,一起相约在苏州见个面。 ...
    小天先森阅读 192评论 0 0
  • 观影时几度含泪,几度心酸,看完后,想谈一谈我对这部影片的解读。 好的影片是那种用故事追问社会与人生的本质问题,即使...
    佳彤阅读 7,274评论 0 3