|
Don asked me to submit my previous posting in pieces. So here is part one: Here is first a C/400 program to print the System Entry Point Table (SEPT). /* Test program to display System Entry Point Table */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> /* qsysinc: */ #include <pointer.h> #include <mimchobs.h> #include <mispcobj.h> #include <miptrnam.h> #include <qliept.h> static _MPTR_Template_T *mptr_area; void main(void){ int i; _OPENPTR *inv_sys; i = sizeof(_MPTR_Template_T); mptr_area = malloc(i); mptr_area->Obj_Ptr.Template_Size = i; for(i=0; i<WLISRHNMTBL_DIM; i++) { inv_sys = (((_SYSPTR **)_SYSEPT()) + i); if (*inv_sys != NULL) { matptr(mptr_area, *inv_sys); printf("Entry %d is %10.10s %10.10s\n", i, mptr_area->Obj_Ptr.Library_ID.Name, mptr_area->Obj_Ptr.Object_ID.Name); } else { printf("Entry %d is **null**\n", i); } } free(mptr_area); } When run under Security Level 30, the program prints out 6245 entries. When run under level 40, the program bombs right away with a 'security violation'. The program uses the MATPTR API, which is documented in the usual AS/400 manuals. Under any Security Level you can always dump the SEPT using the DUMPSYSOBJ command: DMPSYSOBJ OBJ(QINSEPT) CONTEXT(QSYS) When you do that and select the QPSRVDMP spool file with WRKSPLF you see something like the following; find the POINTERS section: Display Spooled File File . . . . . : QPSRVDMP Page/Line 54/47 Control . . . . . Columns 1 - 78 Find . . . . . . POINTERS *...+....1....+....2....+....3....+....4....+....5....+....6....+....7.. .POINTERS- 000000 SYP 02 01 QT3REQIO 04 01 QSYS 000010 SYP 02 01 QWSCLOSE 04 01 QSYS 000020 SYP 02 01 QSFGET 04 01 QSYS 000030 SYP 02 01 QWSOPEN 04 01 QSYS 000040 SYP 02 01 QWSPBDVR 04 01 QSYS 000050 SYP 02 01 QWSRST 04 01 QSYS 000060 SYP 02 01 QWSRTSFL 04 01 QSYS 000070 SYP 02 01 QSFCRT 04 01 QSYS 000080 SYP 02 01 QWSSPEND 04 01 QSYS 000090 SYP 02 01 QDCVRX 04 01 QSYS 0000A0 SYP 02 01 QDMCLOSE 04 01 QSYS 0000B0 SYP 02 01 QDMCOPEN 04 01 QSYS 0000C0 SYP 02 01 QDBCLOSE 04 01 QSYS 0000D0 SYP 02 01 QDBGETDR 04 01 QSYS 0000E0 SYP 02 01 QDBGETKY 04 01 QSYS 0000F0 SYP 02 01 QDBGETSQ 04 01 QSYS 000100 SYP 02 01 QDBOPEN 04 01 QSYS 000110 SYP 02 01 QDBPUT 04 01 QSYS 000120 SYP 02 01 QDBUDR 04 01 QSYS 000130 SYP 02 01 QSPBPPRT 04 01 QSYS 000140 SYP 02 01 QOESETEX 04 01 QSYS 000150 SYP 02 01 QWSPUT 04 01 QSYS 000160 SYP 02 01 QWSMEEH 04 01 QSYS 000170 SYP 02 01 QWSMSG 04 01 QSYS 000180 SYP 02 01 QWSPTMSG 04 01 QSYS 000190 SYP 02 01 QLPCTLIN 04 01 QSYS 0001A0 SYP 02 01 QLPTRANS 04 01 QSYS 0001B0 SYP 02 01 QWCITUNR 04 01 QSYS 0001C0 SYP 02 01 QTIMAIN1 04 01 QSYS . . . etc It takes 144 seconds to produce the dump. The dump shows programs in their context (QSYS). One could capture this output in a file and work on each entry. MI Program DSPSEPT to Materialize the SEPT. For simplicity in experimentation the program sends its resulting output for each entry to the job's message queue. Stop it with the System Request key, then answer '2'. Don't worry about the details, go straight to the discussion after the listing. DCL SPC * BASPCO; DCL SPCPTR .SEPT_PCO DIR; /* 1ST ENTRY */ DCL SYSPTR .SEPT(6440) BAS(.SEPT_PCO); DCL CON MAX_SEPT BIN(2) INIT(6440); /* VERSION DEPENDENT */ DCL DD ENTRY_NBR BIN(2); DCL DD INFO CHAR(77) BDRY(16); DCL DD INFO_PRV BIN ( 4) DEF(INFO) POS( 1) INIT(77); DCL DD INFO_AVL BIN ( 4) DEF(INFO) POS( 5); DCL DD INFO_PTR_TYPE CHAR( 1) DEF(INFO) POS( 9); DCL DD INFO_LIB_ID CHAR(32) DEF(INFO) POS(10); DCL DD INFO_LIB_TYPES CHAR( 2) DEF(INFO_LIB_ID) POS(1); DCL DD INFO_LIB_NAME CHAR(30) DEF(INFO_LIB_ID) POS(3); DCL DD INFO_OBJ_ID CHAR(32) DEF(INFO) POS(42); DCL DD INFO_OBJ_TYPES CHAR( 2) DEF(INFO_OBJ_ID) POS(1); DCL DD INFO_OBJ_NAME CHAR(30) DEF(INFO_OBJ_ID) POS(3); DCL DD INFO_BITS CHAR( 4) DEF(INFO) POS(74); DCL SPCPTR .INFO INIT(INFO); DCL SYSPTR .FORGED; /* SYSTEM POINTER TO FORGE */ DCL INSPTR RETURN; /* RETURN PTR FOR CALLI */ ENTRY * EXT; CPYNV ENTRY_NBR, 0; NEXT_ENTRY: ADDN(S) ENTRY_NBR, 1; SETSPFP .FORGED, .SEPT(ENTRY_NBR); /* FORGE POINTER */ MATPTR .INFO, .FORGED; BRK "1"; CALLI SHOW_OBJECT, *, RETURN; /* SHOW RESULT TO MSGQ */ TEST_ENTRY: CMPNV(B) ENTRY_NBR, MAX_SEPT /LO(NEXT_ENTRY); RTX *; /******* SEND MESSAGE HANDLING ********/ DCL DD MSG_ID CHAR (7) INIT(" "); DCL SPCPTR .MSG_ID INIT(MSG_ID); DCL DD MSG_FILE CHAR(20) INIT(" "); DCL SPCPTR .MSG_FILE INIT(MSG_FILE); DCL DD MSG_TEXT CHAR(74); DCL DD MSG_ENTRY_NBR ZND(4,0) DEF(MSG_TEXT) POS( 1); DCL DD * CHAR( 1) DEF(MSG_TEXT) POS( 5) INIT(":"); DCL DD MSG_OBJ_OBJ CHAR(30) DEF(MSG_TEXT) POS( 6); DCL DD MSG_OBJ_LIB CHAR(30) DEF(MSG_TEXT) POS(36); DCL DD * CHAR( 1) DEF(MSG_TEXT) POS(66) INIT(" "); DCL DD MSG_OBJ_BITS CHAR( 8) DEF(MSG_TEXT) POS(67); DCL SPCPTR .MSG_TEXT INIT(MSG_TEXT); DCL DD MSG_SIZE BIN( 4) INIT(74); DCL SPCPTR .MSG_SIZE INIT(MSG_SIZE); DCL DD MSG_TYPE CHAR(10) INIT("*INFO "); DCL SPCPTR .MSG_TYPE INIT(MSG_TYPE); DCL DD MSG_QS CHAR(20) INIT("*REQUESTER "); DCL SPCPTR .MSG_QS INIT(MSG_QS); DCL DD MSG_QSN BIN( 4) INIT(1); DCL SPCPTR .MSG_QSN INIT(MSG_QSN); DCL DD REPLY_Q CHAR(20) INIT(" "); DCL SPCPTR .REPLY_Q INIT(REPLY_Q); DCL DD MSG_KEY CHAR( 4); DCL SPCPTR .MSG_KEY INIT(MSG_KEY); DCL DD ERR_CODE BIN( 4) INIT(0); DCL SPCPTR .ERR_CODE INIT(ERR_CODE); DCL OL QMHSNDMOL (.MSG_ID, .MSG_FILE, .MSG_TEXT, .MSG_SIZE, .MSG_TYPE, .MSG_QS, .MSG_QSN, .REPLY_Q, .MSG_KEY, .ERR_CODE) ARG; ENTRY SHOW_OBJECT INT; /* SHOW OBJECT INFO */ CPYNV MSG_ENTRY_NBR, ENTRY_NBR; CPYBLA MSG_OBJ_OBJ, INFO_OBJ_NAME; CPYBLA MSG_OBJ_LIB, INFO_LIB_NAME; CVTHC MSG_OBJ_BITS, INFO_BITS; /* HEX TO CHAR */ CALLX .SEPT(4268), QMHSNDMOL, *; /* SEND MSG TO MSGQ */ B RETURN; /******* EXCEPTION HANDLING ********/ DCL EXCM EXCEPTION_MONITOR EXCID(H'0000') /* ALL */ BP(ERROR_DETECTED) IMD; ERROR_DETECTED: CPYBLAP INFO_OBJ_NAME, "*PROTECTED", " "; CPYBLAP INFO_LIB_NAME, "QSYS", " "; CPYBLA INFO_BITS, X'00000000'; CALLI SHOW_OBJECT, *, RETURN; B TEST_ENTRY; PEND; The crucial instructions are: SETSPFP .FORGED, .SEPT(ENTRY_NBR); /* FORGE POINTER */ MATPTR .INFO, .FORGED; If you simply try to materialize the entry point, that is: MATPTR .INFO, .SEPT(ENTRY_NBR); you get an exception ('Object domain or hardware storage protection violation'). By setting another system pointer, .FORGED, from the entry point (the SETSPFP instruction) you essentially forge a new pointer from the old. This new pointer can be materialized in some cases, bypassing the security integrity check for the SEPT object itself. I've marked (with OK) the entries that can be materialized in the following table: 000000 SYP 02 01 QT3REQIO 04 01 QSYS 000010 SYP 02 01 QWSCLOSE 04 01 QSYS 000020 SYP 02 01 QSFGET 04 01 QSYS 000030 SYP 02 01 QWSOPEN 04 01 QSYS 000040 SYP 02 01 QWSPBDVR 04 01 QSYS 000050 SYP 02 01 QWSRST 04 01 QSYS 000060 SYP 02 01 QWSRTSFL 04 01 QSYS 000070 SYP 02 01 QSFCRT 04 01 QSYS 000080 SYP 02 01 QWSSPEND 04 01 QSYS 000090 SYP 02 01 QDCVRX 04 01 QSYS 0000A0 SYP 02 01 QDMCLOSE OK 04 01 QSYS 0000B0 SYP 02 01 QDMCOPEN OK 04 01 QSYS 0000C0 SYP 02 01 QDBCLOSE 04 01 QSYS 0000D0 SYP 02 01 QDBGETDR OK 04 01 QSYS 0000E0 SYP 02 01 QDBGETKY OK 04 01 QSYS 0000F0 SYP 02 01 QDBGETSQ OK 04 01 QSYS 000100 SYP 02 01 QDBOPEN 04 01 QSYS 000110 SYP 02 01 QDBPUT OK 04 01 QSYS 000120 SYP 02 01 QDBUDR OK 04 01 QSYS 000130 SYP 02 01 QSPBPPRT 04 01 QSYS 000140 SYP 02 01 QOESETEX 04 01 QSYS 000150 SYP 02 01 QWSPUT OK 04 01 QSYS 000160 SYP 02 01 QWSMEEH 04 01 QSYS . . . If you display the program information (DSPPGM PGM(QSYS/QDMCLOSE) for two entries (one that can be materialized and one that cannot) you see something like this: Program . . . . . .. . . . . .: QDMCLOSE QDBCLOSE Program creation date/time .. .. : 03/18/98 15:36:56 05/18/98 23:04:18 Type of program . . . . . . . . : OPM OPM Source file . . . . . . . . . . : Library . . . . . . . . . . . : Source member . . . . . . . . . : Source file change date/time . . : Observable information . . . . . : *NONE *NONE User profile . . . . . . . . . . : *USER *USER Use adopted authority . . . . . : *YES *YES Fix decimal data . . . . . . . . : *NO *NO Text description . . . . . . . . : Program size (bytes) . . . . . . : 49152 32768 Associated space size (bytes) . : 0 0 Static storage size (bytes) . . : 0 0 Automatic storage size (bytes) . : 2208 1488 Program state . . . . . . . . . : *SYSTEM *SYSTEM Program domain . . . . . . . . . : *USER *SYSTEM Compiler . . . . . . . . . . . . : V4R3M0 V4R3M0 Earliest release for running. .. : V4R3M0 V4R3M0 Conversion required . . . . . . : *NO *NO Sort sequence . . . . . . . . . : *HEX *HEX Language identifier . . . . . . : *JOBRUN *JOBRUN Optimization . . . . . . . . . . : *OPTIMIZE *OPTIMIZE Paging pool . . . . . . . . . . : *USER *USER Update PASA . . . . . . . . . . : *UPDPASA *NOUPDPASA Clear PASA . . . . . . . . . . . : *CLRPASA *NOCLRPASA Paging amount . . . . . . . . . : *BLOCK *BLOCK The only real difference is that QDMCLOSE is in the *USER domain and QDBCLOSE is in the *SYSTEM domain. To put it differently: QDMCLOSE is for general use (this does not necessarily mean that it is a documented API; e.g. QDBPUT is not) and QDBCLOSE is for system use only. With the MATPTR MI-instruction you had to forge the pointer to access an entry in the SEPT. There is another instruction, Materialize System Object - MATSOBJ, that can materialize a system object; e.g.: MATSOBJ .INFO, .SEPT(ENTRY_NBR); This works directly without using a forged pointer. However, you still cannot materialize objects in the system domain (in spite of the name of the MI-instruction). Why Are We Doing This The System Entry Point Table (SEPT) is important, because the programs in it are before any programs in the library list and are the basic operating system calls (e.g. to open files, read records, etc). If you could place one of your own programs here in lieu of a standard entry point, you could act as a Trojan Horse and essentially bypass most security. A minimum defense against this would be to print a listing of all the programs including their properties. If you are running under at least Security Level 40, you are supposedly protected against tampering with the SEPT so you need only to worry about the entries you can have access to. The problem here is that you want to be *sure* that it has not been tampered with. +--- | This is the MI Programmers Mailing List! | To submit a new message, send your mail to MI400@midrange.com. | To subscribe to this list send email to MI400-SUB@midrange.com. | To unsubscribe from this list send email to MI400-UNSUB@midrange.com. | Questions should be directed to the list owner/operator: dr2@cssas400.com +---
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.